diff --git a/.cargo/release-version b/.cargo/release-version index a7a4bb2332..8503faf3bb 100644 --- a/.cargo/release-version +++ b/.cargo/release-version @@ -1 +1 @@ -v4.7.3 \ No newline at end of file +v4.8.0 \ No newline at end of file diff --git a/.ci/test_dev_on_prod_restart.sh b/.ci/test_dev_on_prod_restart.sh index 60d116535f..0f7d581ea7 100755 --- a/.ci/test_dev_on_prod_restart.sh +++ b/.ci/test_dev_on_prod_restart.sh @@ -128,8 +128,9 @@ function copy_setup_ledger() { # Clear any state cached by a previous test run (proposal cache, dev committee state, etc.). # The ledger we just copied is fresh, so any persisted dev state must be regenerated from it. + # Pass --node-data-storage so clean targets the same custom path start_dev_nodes uses. for i in $(seq 0 $((NUM_DEV_NODES - 1))); do - snarkos clean "--dev=${i}" "--network=0" + snarkos clean "--dev=${i}" "--network=0" --node-data-storage "node-data-${i}" done } diff --git a/.ci/test_devnet.sh b/.ci/test_devnet.sh index 2ec8864434..470d246d9c 100755 --- a/.ci/test_devnet.sh +++ b/.ci/test_devnet.sh @@ -136,6 +136,10 @@ function main: add r0 r1 into r2; output r2 as u32.private; +view compute_sum: + add 1u32 2u32 into r0; + output r0 as u32.public; + constructor: assert.eq true true; " > program/main.aleo @@ -187,6 +191,36 @@ else exit 1 fi +# Query the view function at the latest height. +log "● Testing view function evaluation at latest height..." +view_response=$(curl -s -X POST \ + -H "Content-Type: application/json" \ + -d '[]' \ + "http://localhost:3030/v2/$network_name/program/${program_name}/view/compute_sum") +view_output=$(jq -r '.[0]' <<< "$view_response") +if [ "$view_output" = "3u32" ]; then + log "✅ View function returned expected output at latest height: $view_output" +else + log "❌ Test failed! View function returned unexpected output at latest height: $view_response" + exit 1 +fi + +# Query the view function at a specific block height. +# Requires history feature. +# log "● Testing view function evaluation at specific block height..." +# current_height=$(curl -s "http://localhost:3030/v2/$network_name/block/height/latest") +# view_response=$(curl -s -X POST \ +# -H "Content-Type: application/json" \ +# -d '[]' \ +# "http://localhost:3030/v2/$network_name/program/${program_name}/view/compute_sum/${current_height}") +# view_output=$(jq -r '.[0]' <<< "$view_response") +# if [ "$view_output" = "3u32" ]; then +# log "✅ View function returned expected output at height ${current_height}: $view_output" +# else +# log "❌ Test failed! View function returned unexpected output at height ${current_height}: $view_response" +# exit 1 +# fi + # Execute a function in the deployed program and wait for the execution to be processed. log "● Testing program execution with V2 API..." execute_result=$(cd program && snarkos developer execute --dev-key 0 --network "$network_id" --broadcast --endpoint=http://localhost:3030 \ @@ -232,6 +266,47 @@ if [ "$rest_status" != "accepted" ]; then exit 1 fi +log "✅ Confirmed transaction endpoint returned status \"accepted\"" + +# Broadcast a transfer_public with an impossibly large amount so the transaction is rejected on finalize. +log "● Testing transaction rejection reason endpoint..." +recipient=$(curl -s "http://$localhost:3030/v2/$network_name/committee/latest" | jq -r '.members | keys[1]') +if [ -z "$recipient" ] || [ "$recipient" = "null" ]; then + log "❌ Test failed! Could not retrieve a recipient address from the committee." + exit 1 +fi + +rejected_execute_result=$(snarkos developer execute --dev-key 0 --network "$network_id" \ + --broadcast --endpoint="http://$localhost:3030" --wait --timeout 60 \ + credits.aleo transfer_public "$recipient" 18446744073709551615u64) +rejected_tx=$(echo "$rejected_execute_result" | tail -n 1) + +rest_rejected=$(curl -s "http://$localhost:3030/v2/$network_name/transaction/confirmed/$rejected_tx") +rest_status=$(jq --raw-output '.status' <<< "$rest_rejected") +if [ "$rest_status" != "rejected" ]; then + printf "❌ Test failed! Expected transaction to be rejected, but status was: \"%s\"\nFull JSON: %s\n" \ + "$rest_status" "$rest_rejected" + exit 1 +fi + +rejection_reason=$(curl -s "http://$localhost:3030/v2/$network_name/transaction/rejected/$rejected_tx/reason") +rejection_reason_status=$(curl -s -o /dev/null -w "%{http_code}" \ + "http://$localhost:3030/v2/$network_name/transaction/rejected/$rejected_tx/reason") +if (( rejection_reason_status != 200 )); then + log "❌ Test failed! Rejection reason endpoint returned $rejection_reason_status instead of 200: $rejection_reason" + exit 1 +fi + +rejection_type=$(jq --raw-output '.type' <<< "$rejection_reason") +rejection_program=$(jq --raw-output '.program_id' <<< "$rejection_reason") +rejection_resource=$(jq --raw-output '.resource' <<< "$rejection_reason") +if [ "$rejection_type" != "finalize" ] || [ "$rejection_program" != "credits.aleo" ] || [ "$rejection_resource" != "transfer_public" ]; then + log "❌ Test failed! Unexpected rejection reason: $rejection_reason" + exit 1 +fi + +log "✅ Rejection reason retrieved successfully for rejected transfer_public transaction" + log "ℹ️Testing REST API and REST Error Handling" # Test invalid transaction data (JsonDataError) returns 422 Unprocessable Content diff --git a/.circleci/config.yml b/.circleci/config.yml index c28337e7c0..6dd2f53540 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -124,7 +124,7 @@ commands: name: Install Debian packages command: | DEBIAN_FRONTEND=noninteractive sudo apt-get update - DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends clang llvm-dev llvm lld pkg-config xz-utils make libssl-dev libssl-dev jq iproute2 + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-recommends clang libclang-dev llvm-dev llvm lld pkg-config xz-utils make libssl-dev libssl-dev jq iproute2 - restore_cache: keys: - << parameters.cache_key >> @@ -760,7 +760,7 @@ jobs: - run: name: Lint scripts command: | - shellcheck -x .ci/*.sh + shellcheck -x .ci/*.sh scripts/*.sh - clear_environment: cache_key: v4.2.0-rust-1.88.0-lint-scripts-cache @@ -816,7 +816,7 @@ workflows: filters: branches: only: - - test_fixed_dev_committee + - main_net_v48 - canary - testnet - mainnet @@ -826,7 +826,7 @@ workflows: filters: branches: only: - - release-mainnet-4.7.3 + - main_net_v48 - canary - testnet - mainnet @@ -836,7 +836,7 @@ workflows: filters: branches: only: - - release-mainnet-4.7.3 + - main_net_v48 - canary - testnet - mainnet @@ -845,7 +845,7 @@ workflows: filters: branches: only: - - release-mainnet-4.7.3 + - main_net_v48 - canary - testnet - mainnet diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 97e80f4e4f..071e722088 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -4,7 +4,7 @@ on: push: branches: - 'staging' - - 'release-mainnet-4.7.3' + - 'main_net_v48' workflow_dispatch: jobs: @@ -25,7 +25,7 @@ jobs: - name: Install required Debian packages run: | sudo apt-get update - sudo apt-get install -y lld python3-pip + sudo apt-get install -y lld libclang-dev python3-pip - name: Set up Python virtual environment run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2b19b9ac80..30e482d7c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Install required Debian pacakges - run: sudo apt install -y lld + run: sudo apt install -y lld libclang-dev - name: Build snarkOS run: | diff --git a/.rusty-hook.toml b/.rusty-hook.toml index 4b16714fe8..83f86e26ce 100644 --- a/.rusty-hook.toml +++ b/.rusty-hook.toml @@ -1,5 +1,5 @@ [hooks] -pre-commit = "cargo clippy --workspace --all-targets --all-features -- -D warnings && cargo +nightly fmt --all -- --check" +pre-commit = "./scripts/lint.sh" [logging] verbose = true diff --git a/Cargo.lock b/Cargo.lock index 6568a6d80b..73bd6d11ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9ebd144c81671193ed85aa2db9bb5e183421843e0485de8fffc07e5cf50e18a" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "syn 1.0.109", ] @@ -93,7 +93,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f6ff9e4c36858fa2c29e5284b77527b5a7466743976e1ba1f5824e16683545" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "syn 1.0.109", ] @@ -173,9 +173,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] [[package]] name = "arbitrary" @@ -194,9 +203,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" [[package]] name = "async-recursion" @@ -205,8 +214,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -216,8 +225,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -276,7 +285,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.10.0", + "hyper 1.10.1", "hyper-util", "itoa", "matchit", @@ -396,23 +405,20 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.65.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.13.0", "cexpr", "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "prettyplease", + "itertools 0.13.0", "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.117", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.118", ] [[package]] @@ -453,9 +459,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "blake2" @@ -488,9 +494,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -509,9 +515,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145" dependencies = [ "bytes", "cfg_aliases", @@ -541,6 +547,12 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + [[package]] name = "bytemuck" version = "1.25.0" @@ -555,9 +567,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" [[package]] name = "bzip2-sys" @@ -580,14 +592,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 2.0.1", ] [[package]] @@ -613,9 +625,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cpufeatures 0.3.0", @@ -624,9 +636,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", @@ -651,7 +663,6 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading", ] [[package]] @@ -684,8 +695,8 @@ checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -705,9 +716,9 @@ dependencies = [ [[package]] name = "cmov" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "colorchoice" @@ -925,6 +936,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -965,7 +982,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "crossterm_winapi", "derive_more", "document-features", @@ -994,9 +1011,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" dependencies = [ "cpubits", "ctutils", @@ -1070,8 +1087,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1092,9 +1109,9 @@ checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ "ident_case", "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1104,8 +1121,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1164,7 +1181,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -1175,9 +1191,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bba95f299f6b9cd47f68a847eca2ae9060a2713af532dc35c342065544845407" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "structmeta 0.3.0", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1187,8 +1203,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1208,9 +1224,9 @@ checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case", "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "rustc_version", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1230,7 +1246,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "const-oid 0.10.2", "crypto-common 0.2.2", "ctutils", @@ -1263,8 +1279,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1395,8 +1411,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1417,18 +1433,19 @@ dependencies = [ [[package]] name = "env_filter" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" dependencies = [ "log", + "regex", ] [[package]] name = "env_logger" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", @@ -1481,6 +1498,12 @@ dependencies = [ "regex", ] +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + [[package]] name = "fastrand" version = "2.4.1" @@ -1661,8 +1684,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -1757,16 +1780,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", "rand_core 0.10.1", - "wasip2", - "wasip3", ] [[package]] @@ -1781,7 +1802,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "libc", "libgit2-sys", "log", @@ -1818,9 +1839,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -1877,6 +1898,11 @@ name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hdrhistogram" @@ -2033,9 +2059,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "subtle", "typenum", @@ -2067,9 +2093,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -2094,7 +2120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http 1.3.1", - "hyper 1.10.0", + "hyper 1.10.1", "hyper-util", "rustls", "tokio", @@ -2108,7 +2134,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ - "hyper 1.10.0", + "hyper 1.10.1", "hyper-util", "pin-project-lite", "tokio", @@ -2136,7 +2162,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.10.0", + "hyper 1.10.1", "hyper-util", "native-tls", "tokio", @@ -2156,12 +2182,12 @@ dependencies = [ "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper 1.10.0", + "hyper 1.10.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.3", + "socket2 0.6.4", "system-configuration", "tokio", "tower-service", @@ -2275,12 +2301,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -2363,8 +2383,8 @@ dependencies = [ "darling", "indoc", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -2398,6 +2418,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -2437,10 +2466,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "rustc_version", "simd_cesu8", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2458,8 +2487,8 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -2474,13 +2503,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -2545,18 +2573,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" version = "0.2.186" @@ -2565,9 +2581,9 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libgit2-sys" -version = "0.18.4+1.9.3" +version = "0.18.5+1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b26f66f35e1871b22efcf7191564123d2a446ca0538cde63c23adfefa9b15b7" +checksum = "005d6ae6eac1912906073e069f7db60b1fa98e052a68227824afe3e3a1c59ca2" dependencies = [ "cc", "libc", @@ -2602,14 +2618,13 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.11.0+8.1.1" +version = "0.17.3+10.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" +checksum = "cef2a00ee60fe526157c9023edab23943fae1ce2ab6f4abb2a807c1746835de9" dependencies = [ "bindgen", "bzip2-sys", "cc", - "glob", "libc", "libz-sys", "lz4-sys", @@ -2617,9 +2632,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "libc", @@ -2633,7 +2648,7 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -2689,9 +2704,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" @@ -2702,6 +2717,15 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "lru" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +dependencies = [ + "hashbrown 0.17.1", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2745,9 +2769,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "memmem" @@ -2842,9 +2866,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", @@ -2874,8 +2898,8 @@ checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" dependencies = [ "cfg-if", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -2907,7 +2931,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -2920,7 +2944,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "cfg_aliases", "libc", @@ -2987,8 +3011,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -3066,11 +3090,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.80" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cfg-if", "foreign-types", "libc", @@ -3085,8 +3109,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -3097,9 +3121,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.116" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -3122,6 +3146,30 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote 1.0.46", + "syn 2.0.118", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -3177,12 +3225,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c4e8e2dd832fd76346468f822e4e600d30ba4e5aa545a128abf12cfae7ea3e" -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pem" version = "3.0.6" @@ -3237,8 +3279,8 @@ dependencies = [ "pest", "pest_meta", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -3290,8 +3332,8 @@ dependencies = [ "phf_generator", "phf_shared", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -3319,8 +3361,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -3401,16 +3443,6 @@ dependencies = [ "termtree", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -3428,13 +3460,13 @@ checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.11.1", + "bitflags 2.13.0", "lazy_static", "num-traits", "rand 0.8.6", "rand_chacha 0.3.1", "rand_xorshift 0.3.0", - "regex-syntax 0.8.10", + "regex-syntax 0.8.11", "rusty-fork", "tempfile", "unarray", @@ -3442,9 +3474,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", "prost-derive", @@ -3452,22 +3484,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", - "itertools", + "itertools 0.14.0", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] name = "prost-types" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ "prost", ] @@ -3504,18 +3536,18 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.2", + "rustc-hash", "rustls", - "socket2 0.6.3", + "socket2 0.6.4", "thiserror 2.0.18", "tokio", "tracing", @@ -3524,9 +3556,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" dependencies = [ "aws-lc-rs", "bytes", @@ -3534,7 +3566,7 @@ dependencies = [ "lru-slab", "rand 0.9.4", "ring", - "rustc-hash 2.1.2", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -3553,7 +3585,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.3", + "socket2 0.6.4", "tracing", "windows-sys 0.60.2", ] @@ -3566,9 +3598,9 @@ checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -3613,7 +3645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20", - "getrandom 0.4.2", + "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -3701,31 +3733,35 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.30.0" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc" +checksum = "3274ba0a2c5e1bcad2a2005d20f4dc59dad26b2eb0940fb094500dba4099d57d" dependencies = [ "instability", "ratatui-core", "ratatui-crossterm", "ratatui-macros", + "ratatui-termina", "ratatui-termwiz", "ratatui-widgets", + "serde", ] [[package]] name = "ratatui-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" +checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "compact_str", - "hashbrown 0.16.1", - "indoc", - "itertools", + "critical-section", + "hashbrown 0.17.1", + "itertools 0.14.0", "kasuari", - "lru", + "lru 0.18.0", + "palette", + "serde", "strum", "thiserror 2.0.18", "unicode-segmentation", @@ -3735,9 +3771,9 @@ dependencies = [ [[package]] name = "ratatui-crossterm" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3" +checksum = "567584a3b0e6a8203c23de40b4861497266725eb5363dbfd18a1edd603cca9f0" dependencies = [ "cfg-if", "crossterm", @@ -3747,19 +3783,30 @@ dependencies = [ [[package]] name = "ratatui-macros" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f1342a13e83e4bb9d0b793d0ea762be633f9582048c892ae9041ef39c936f4" +checksum = "ed7dc68daa7498a43e4d68e0eb078427e10c38fbcfbb1e42d955f1fa2140d814" dependencies = [ "ratatui-core", "ratatui-widgets", ] [[package]] -name = "ratatui-termwiz" +name = "ratatui-termina" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f76fe0bd0ed4295f0321b1676732e2454024c15a35d01904ddb315afd3d545c" +checksum = "c0bf912d9e66f057a759d92e386a280ea886b352ab757d6ac4d653c7ed2c43c2" +dependencies = [ + "instability", + "ratatui-core", + "termina", +] + +[[package]] +name = "ratatui-termwiz" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf03e0380b7744054d6cb74224fe3adf062a029754933f575ca1e3b4c2ce977" dependencies = [ "ratatui-core", "termwiz", @@ -3767,17 +3814,18 @@ dependencies = [ [[package]] name = "ratatui-widgets" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db" +checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags 2.11.1", - "hashbrown 0.16.1", + "bitflags 2.13.0", + "hashbrown 0.17.1", "indoc", "instability", - "itertools", + "itertools 0.14.0", "line-clipping", "ratatui-core", + "serde", "strum", "time", "unicode-segmentation", @@ -3790,7 +3838,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -3819,7 +3867,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -3849,20 +3897,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.14", - "regex-syntax 0.8.10", + "regex-syntax 0.8.11", ] [[package]] @@ -3882,7 +3930,7 @@ checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.10", + "regex-syntax 0.8.11", ] [[package]] @@ -3893,9 +3941,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" @@ -3913,7 +3961,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.10.0", + "hyper 1.10.1", "hyper-rustls", "hyper-tls 0.6.0", "hyper-util", @@ -3966,11 +4014,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rlimit" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f35ee2729c56bb610f6dba436bf78135f728b7373bdffae2ec815b2d3eb98cc3" +dependencies = [ + "libc", +] + [[package]] name = "rocksdb" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" +checksum = "ddb7af00d2b17dbd07d82c0063e25411959748ff03e8d4f96134c2ff41fce34f" dependencies = [ "libc", "librocksdb-sys", @@ -3978,9 +4035,9 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.5.3" +version = "7.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835a57a69104632d64deb0df2e09a69945cd7a6eab4070fc9b1d7e50cf6c3edc" +checksum = "2da316a15f47e3d053de9cb2c439650bd8fa4aaeb9365f2e5f27f492ff73c196" dependencies = [ "libc", "rtoolbox", @@ -4003,12 +4060,6 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.2" @@ -4051,7 +4102,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -4064,7 +4115,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys 0.12.1", @@ -4073,9 +4124,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", "log", @@ -4089,9 +4140,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -4252,7 +4303,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4341,8 +4392,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -4393,9 +4444,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", "bs58", @@ -4413,14 +4464,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -4471,6 +4522,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook" version = "0.3.18" @@ -4585,9 +4642,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "smol_str" @@ -4610,10 +4667,11 @@ dependencies = [ [[package]] name = "snarkos" -version = "4.7.5" +version = "4.8.0" dependencies = [ "built", "clap", + "crypto-bigint", "elliptic-curve", "locktick", "rusty-hook", @@ -4663,6 +4721,7 @@ dependencies = [ "rand 0.10.1", "rand_chacha 0.10.0", "rayon", + "rlimit", "rpassword", "self_update", "serde", @@ -4707,13 +4766,14 @@ dependencies = [ "anyhow", "async-trait", "bytes", + "cfg-if", "colored 3.1.1", "deadline", "futures-util", "http 1.3.1", "indexmap 2.14.0", "locktick", - "lru", + "lru 0.16.4", "num_cpus", "parking_lot", "paste", @@ -4757,9 +4817,9 @@ dependencies = [ "deadline", "futures", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "locktick", - "lru", + "lru 0.16.4", "mockall", "open", "parking_lot", @@ -4826,7 +4886,6 @@ dependencies = [ "locktick", "parking_lot", "rand 0.10.1", - "rand_chacha 0.10.0", "rayon", "snarkos-node-metrics", "snarkos-utilities", @@ -4844,7 +4903,7 @@ dependencies = [ "anyhow", "indexmap 2.14.0", "locktick", - "lru", + "lru 0.16.4", "parking_lot", "snarkvm", "tracing", @@ -4881,9 +4940,9 @@ dependencies = [ "cfg-if", "colored 3.1.1", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "locktick", - "lru", + "lru 0.16.4", "once_cell", "parking_lot", "snarkos-account", @@ -4926,7 +4985,7 @@ dependencies = [ "snarkos-node-network", "snarkos-node-tcp", "snarkvm", - "socket2 0.6.3", + "socket2 0.6.4", "tokio", "tracing", ] @@ -4945,7 +5004,7 @@ dependencies = [ "indexmap 2.14.0", "jsonwebtoken", "locktick", - "lru", + "lru 0.16.4", "once_cell", "parking_lot", "rand 0.10.1", @@ -5026,7 +5085,7 @@ dependencies = [ "anyhow", "futures", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "locktick", "parking_lot", "rand 0.10.1", @@ -5096,7 +5155,7 @@ dependencies = [ [[package]] name = "snarkvm" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "dotenvy", @@ -5121,7 +5180,7 @@ dependencies = [ [[package]] name = "snarkvm-algorithms" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", @@ -5131,7 +5190,7 @@ dependencies = [ "hashbrown 0.15.5", "hex", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "num-traits", "rand 0.10.1", "rayon", @@ -5149,18 +5208,18 @@ dependencies = [ [[package]] name = "snarkvm-algorithms-cuda" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "blst", "cc", "sppark", - "which 8.0.2", + "which 8.0.4", ] [[package]] name = "snarkvm-circuit" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -5174,7 +5233,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-account" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-network", "snarkvm-circuit-types", @@ -5184,7 +5243,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-algorithms" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-types", "snarkvm-console-algorithms", @@ -5194,7 +5253,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-collections" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-types", @@ -5204,11 +5263,11 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "nom", "num-traits", "smallvec", @@ -5224,12 +5283,12 @@ dependencies = [ [[package]] name = "snarkvm-circuit-environment-witness" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" [[package]] name = "snarkvm-circuit-network" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-algorithms", "snarkvm-circuit-collections", @@ -5240,7 +5299,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-program" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-account", "snarkvm-circuit-algorithms", @@ -5254,7 +5313,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-address", @@ -5269,7 +5328,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-address" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5282,7 +5341,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-boolean" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-console-types-boolean", @@ -5291,7 +5350,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-field" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5301,7 +5360,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-group" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5313,7 +5372,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-integers" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5325,7 +5384,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-scalar" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5336,7 +5395,7 @@ dependencies = [ [[package]] name = "snarkvm-circuit-types-string" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-circuit-environment", "snarkvm-circuit-types-boolean", @@ -5348,7 +5407,7 @@ dependencies = [ [[package]] name = "snarkvm-console" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-account", "snarkvm-console-algorithms", @@ -5361,7 +5420,7 @@ dependencies = [ [[package]] name = "snarkvm-console-account" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "bs58", "snarkvm-console-network", @@ -5372,7 +5431,7 @@ dependencies = [ [[package]] name = "snarkvm-console-algorithms" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "blake2s_simd", "hex", @@ -5388,7 +5447,7 @@ dependencies = [ [[package]] name = "snarkvm-console-collections" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "locktick", @@ -5402,7 +5461,7 @@ dependencies = [ [[package]] name = "snarkvm-console-network" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "enum-iterator", @@ -5422,11 +5481,11 @@ dependencies = [ [[package]] name = "snarkvm-console-network-environment" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "bech32", - "itertools", + "itertools 0.14.0", "nom", "num-traits", "rand 0.10.1", @@ -5440,7 +5499,7 @@ dependencies = [ [[package]] name = "snarkvm-console-program" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "enum-iterator", "enum_index", @@ -5461,7 +5520,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-address", @@ -5476,7 +5535,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-address" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5487,7 +5546,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-boolean" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", ] @@ -5495,7 +5554,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-field" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5505,7 +5564,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-group" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5516,7 +5575,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-integers" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5527,7 +5586,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-scalar" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5538,7 +5597,7 @@ dependencies = [ [[package]] name = "snarkvm-console-types-string" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console-network-environment", "snarkvm-console-types-boolean", @@ -5549,7 +5608,7 @@ dependencies = [ [[package]] name = "snarkvm-curves" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "rand 0.10.1", "rustc_version", @@ -5562,11 +5621,11 @@ dependencies = [ [[package]] name = "snarkvm-fields" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", - "itertools", + "itertools 0.14.0", "num-traits", "rand 0.10.1", "rayon", @@ -5579,13 +5638,14 @@ dependencies = [ [[package]] name = "snarkvm-ledger" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", + "cfg-if", "indexmap 2.14.0", "locktick", - "lru", + "lru 0.16.4", "parking_lot", "rand 0.10.1", "rand_chacha 0.10.0", @@ -5611,7 +5671,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-authority" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "rand 0.10.1", @@ -5623,11 +5683,11 @@ dependencies = [ [[package]] name = "snarkvm-ledger-block" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "rayon", "serde_json", "snarkvm-console", @@ -5647,7 +5707,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-committee" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "indexmap 2.14.0", @@ -5666,7 +5726,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-ledger-narwhal-batch-certificate", "snarkvm-ledger-narwhal-batch-header", @@ -5679,7 +5739,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-certificate" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "indexmap 2.14.0", "rayon", @@ -5692,7 +5752,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-batch-header" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "indexmap 2.14.0", "rayon", @@ -5704,7 +5764,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-data" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "bytes", "serde_json", @@ -5715,7 +5775,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-subdag" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "indexmap 2.14.0", "rayon", @@ -5730,7 +5790,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "bytes", "serde_json", @@ -5743,7 +5803,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-narwhal-transmission-id" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "snarkvm-console", "snarkvm-ledger-puzzle", @@ -5752,14 +5812,14 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", "bincode", "indexmap 2.14.0", "locktick", - "lru", + "lru 0.16.4", "parking_lot", "rand 0.10.1", "rand_chacha 0.10.0", @@ -5773,14 +5833,14 @@ dependencies = [ [[package]] name = "snarkvm-ledger-puzzle-epoch" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", "colored 3.1.1", "indexmap 2.14.0", "locktick", - "lru", + "lru 0.16.4", "parking_lot", "rand 0.10.1", "rand_chacha 0.10.0", @@ -5796,7 +5856,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-query" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "async-trait", @@ -5813,7 +5873,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-store" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std-storage", "anyhow", @@ -5842,7 +5902,7 @@ dependencies = [ [[package]] name = "snarkvm-ledger-test-helpers" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", @@ -5860,7 +5920,7 @@ dependencies = [ [[package]] name = "snarkvm-metrics" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "metrics", ] @@ -5868,7 +5928,7 @@ dependencies = [ [[package]] name = "snarkvm-parameters" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", @@ -5891,7 +5951,7 @@ dependencies = [ [[package]] name = "snarkvm-slipstream-plugin-interface" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", ] @@ -5899,7 +5959,7 @@ dependencies = [ [[package]] name = "snarkvm-slipstream-plugin-manager" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "json5", @@ -5913,14 +5973,14 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "locktick", - "lru", + "lru 0.16.4", "parking_lot", "rand 0.10.1", "rayon", @@ -5928,6 +5988,7 @@ dependencies = [ "snarkvm-algorithms", "snarkvm-circuit", "snarkvm-console", + "snarkvm-ledger-authority", "snarkvm-ledger-block", "snarkvm-ledger-committee", "snarkvm-ledger-narwhal-data", @@ -5948,7 +6009,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-error" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "anyhow", "snarkvm-circuit-environment", @@ -5960,12 +6021,12 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-process" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "colored 3.1.1", "indexmap 2.14.0", - "itertools", + "itertools 0.14.0", "locktick", "parking_lot", "rand 0.10.1", @@ -5987,7 +6048,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-program" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "enum-iterator", "indexmap 2.14.0", @@ -6008,7 +6069,7 @@ dependencies = [ [[package]] name = "snarkvm-synthesizer-snark" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "bincode", "serde_json", @@ -6021,7 +6082,7 @@ dependencies = [ [[package]] name = "snarkvm-utilities" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "aleo-std", "anyhow", @@ -6044,11 +6105,11 @@ dependencies = [ [[package]] name = "snarkvm-utilities-derives" version = "4.7.3" -source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=a108e8159#a108e8159c8b26a19fbe25bd51a5de9a645796a3" +source = "git+https://github.com/ProvableHQ/snarkVM.git?rev=293c55f15#293c55f157f8b396861113bf0c80450f1f9b59c1" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6063,9 +6124,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -6103,9 +6164,9 @@ dependencies = [ [[package]] name = "sppark" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c900139f3f6fdc8db217881a946adf00e935102fdd82b0e1bc19bacbffa311" +checksum = "bfae3f3e0559cf04e9d9abce56d1db0dab58e03874cf4db5546540710740cfea" dependencies = [ "cc", "which 4.4.2", @@ -6136,9 +6197,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "structmeta-derive 0.2.0", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6148,9 +6209,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "structmeta-derive 0.3.0", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6160,8 +6221,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6171,29 +6232,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] name = "strum" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.27.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" dependencies = [ "heck", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6210,7 +6271,7 @@ checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" dependencies = [ "quote 0.3.15", "synom", - "unicode-xid 0.0.4", + "unicode-xid", ] [[package]] @@ -6220,18 +6281,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "unicode-ident", ] @@ -6250,7 +6311,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" dependencies = [ - "unicode-xid 0.0.4", + "unicode-xid", ] [[package]] @@ -6260,8 +6321,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6280,7 +6341,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6302,12 +6363,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", "rustix 1.1.4", "windows-sys 0.61.2", ] +[[package]] +name = "termina" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" +dependencies = [ + "bitflags 2.13.0", + "parking_lot", + "rustix 1.1.4", + "signal-hook", + "windows-sys 0.61.2", +] + [[package]] name = "terminfo" version = "0.9.0" @@ -6343,7 +6417,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64 0.22.1", - "bitflags 2.11.1", + "bitflags 2.13.0", "fancy-regex", "filedescriptor", "finl_unicode", @@ -6390,22 +6464,22 @@ dependencies = [ [[package]] name = "test-log-core" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d4d41320b48bc4a211a9021678fcc0c99569b594ea31c93735b8e517102b4c" +checksum = "c26ef8b00e4d382e59f6a8ddb3cd790b3a5bb29f21a358a9a69ea2f29f13f27b" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] name = "test-log-macros" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9beb9249a81e430dffd42400a49019bcf548444f1968ff23080a625de0d4d320" +checksum = "944ad38adcbb71eaa682c56bceeb079e4ca82b4b3edc2a0fde5cb297b77dac8d" dependencies = [ - "syn 2.0.117", + "syn 2.0.118", "test-log-core", ] @@ -6416,9 +6490,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8361c808554228ad09bfed70f5c823caf8a3450b6881cc3a38eb57e8c08c1d9" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "structmeta 0.2.0", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6429,9 +6503,9 @@ checksum = "8f7fd1eb9efb36942b85a290c4201d317980fe09bc88d34dd48aaaae03075c6a" dependencies = [ "derive-ex", "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "structmeta 0.3.0", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6459,8 +6533,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6470,8 +6544,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6514,12 +6588,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -6531,15 +6604,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" dependencies = [ "num-conv", "time-core", @@ -6591,7 +6664,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.3", + "socket2 0.6.4", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -6604,8 +6677,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6725,12 +6798,12 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.10.0", + "hyper 1.10.1", "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.3", + "socket2 0.6.4", "sync_wrapper", "tokio", "tokio-stream", @@ -6776,7 +6849,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "bytes", "futures-core", "futures-util", @@ -6845,8 +6918,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6905,8 +6978,8 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad06847b7afb65c7866a36664b75c40b895e318cea4f71299f013fb22965329d" dependencies = [ - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -6927,9 +7000,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "ucd-trie" @@ -6957,9 +7030,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" @@ -6967,7 +7040,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5" dependencies = [ - "itertools", + "itertools 0.14.0", "unicode-segmentation", "unicode-width", ] @@ -6984,12 +7057,6 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "unit-prefix" version = "0.5.2" @@ -7077,12 +7144,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "atomic", - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", "wasm-bindgen", ] @@ -7150,27 +7217,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -7181,9 +7239,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -7191,75 +7249,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ - "quote 1.0.45", + "quote 1.0.46", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.1", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -7277,18 +7301,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] @@ -7348,7 +7372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c0cf2d539c645b448eaffec9ec494b8b19bd5077d9e58cb1ae7efece8d575b" dependencies = [ "proc-macro2", - "quote 1.0.45", + "quote 1.0.46", "syn 1.0.109", ] @@ -7379,9 +7403,9 @@ dependencies = [ [[package]] name = "which" -version = "8.0.2" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" +checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" dependencies = [ "libc", ] @@ -7437,8 +7461,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -7448,8 +7472,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -7664,100 +7688,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - [[package]] name = "wit-bindgen" version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.14.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.1", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid 0.2.6", - "wasmparser", -] - [[package]] name = "writeable" version = "0.6.3" @@ -7766,9 +7702,9 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -7782,29 +7718,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.49" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.49" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -7823,29 +7759,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -7877,8 +7813,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", - "quote 1.0.45", - "syn 2.0.117", + "quote 1.0.46", + "syn 2.0.118", ] [[package]] @@ -7908,9 +7844,9 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" +checksum = "977347db8caa080403f6b6b7c1cda9479a8e869316f7e13a59b19076a40f94e3" [[package]] name = "zmij" diff --git a/Cargo.toml b/Cargo.toml index 8cd452f7ba..22d3534500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snarkos" -version = "4.7.5" +version = "4.8.0" authors = [ "The Aleo Team " ] description = "A decentralized operating system" homepage = "https://aleo.org" @@ -48,10 +48,8 @@ default-features = false [workspace.dependencies.snarkvm] #path = "../snarkVM" git = "https://github.com/ProvableHQ/snarkVM.git" -rev = "a108e8159" +rev = "293c55f15" #version = "=4.7.3" -default-features = false - [workspace.dependencies.anyhow] version = "1.0" @@ -271,7 +269,7 @@ name = "snarkos" path = "snarkos/main.rs" [features] -default = [ "snarkos-cli/metrics", "snarkos-node-metrics", "snarkos-node/metrics", "snarkos-node-cdn/metrics" ] +default = [ "snarkos-cli/metrics", "snarkos-node-metrics", "snarkos-node/metrics", "snarkos-node-cdn/metrics", "telemetry" ] history = [ "snarkos-node/history" ] history-staking-rewards = [ "snarkos-node/history-staking-rewards" ] slipstream-plugins = [ "snarkos-node/slipstream-plugins", "snarkos-cli/slipstream-plugins" ] @@ -374,6 +372,12 @@ workspace = true version = "=0.14.0-rc.29" default-features = false +# Pinned alongside elliptic-curve to avoid resolving yanked crypto-bigint releases. +[dependencies.crypto-bigint] +version = "=0.7.5" +default-features = false +features = ["hybrid-array", "rand_core", "subtle", "zeroize"] + [dev-dependencies.rusty-hook] version = "0.11.2" @@ -422,6 +426,7 @@ debug-assertions = true [package.metadata.cargo-machete] ignored = [ "elliptic-curve", # Needed to pin the crate to a specific version + "crypto-bigint", # Needed to pin the crate to a specific version "snarkos-account", # Needed for cuda feature "snarkos-node", # Needed for metrics feature "snarkos-node-bft", # Needed for cuda and locktick features diff --git a/README.md b/README.md index c82486726e..d7556dbab6 100644 --- a/README.md +++ b/README.md @@ -189,9 +189,9 @@ To start a validator, you can also run the following command from the `snarkOS` ./scripts/run-validator.sh ``` -### 3.2.1 Enable Validator Telemetry Metrics (Optional) +### 3.2.1 Validator Telemetry Metrics -Validator telemetry allows you to track participation in consensus. This is optional and can be enabled using the `telemetry` feature flag. +Validator telemetry allows you to track participation in consensus. This is enabled by default in the standard build. Once enabled, telemetry metrics are available through: @@ -202,21 +202,18 @@ Once enabled, telemetry metrics are available through: // GET /{network}/validators/participation?metadata={true} ``` -You can enable telemetry in one of the following ways: +Telemetry is enabled by default, and you can still explicitly specify the `telemetry` feature flag: -#### 1. Enable via [installation](#2.3-installation) +#### 1. [Installation](#2.3-installation) -Add the `telemetry` feature flag to the installation command. +Use the default installation command: ``` -cargo install --locked --path . --features telemetry +cargo install --locked --path . ``` -#### 2. Enable via `./run-validator.sh` +#### 2. `./run-validator.sh` -Run the `./scripts/run-validator.sh` script and enable telemetry when prompted: -``` -Do you want to enable validator telemetry? (y/n, default: y): -``` +Telemetry is included by default when running `./scripts/run-validator.sh`. ## 3.3 Run an Aleo Prover @@ -589,7 +586,7 @@ cargo run --release -- clean --dev ## 6.4 Feature Flags -By default, the metrics feature is turned on for some internal crates. +By default, the metrics and telemetry features are turned on for some internal crates. * **history** - Enables a /history REST endpoint. diff --git a/build.rs b/build.rs index ec34fc278c..5287d05f5c 100644 --- a/build.rs +++ b/build.rs @@ -25,6 +25,9 @@ use std::{ use toml::Value; use walkdir::WalkDir; +#[path = "version_env.rs"] +mod version_env; + // The following license text that should be present at the beginning of every source file. const EXPECTED_LICENSE_TEXT: &[u8] = include_bytes!(".resources/license_header"); @@ -312,6 +315,8 @@ fn main() { // Check if the tokio_console feature is correctly enabled. check_tokio_console_flags(); + // Register the release version for runtime version reporting. + version_env::emit_version_env(); // Register build-time information. built::write_built_file().expect("Failed to acquire build-time information"); } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0f93742b48..08d361990c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -42,6 +42,7 @@ test_consensus_heights = [ "snarkvm/test_consensus_heights" ] test_network = [ "test_targets", "test_consensus_heights", + "snarkvm/dev-committee", "snarkvm/dev-print" ] serial = [ @@ -181,3 +182,6 @@ features = [ "test-helpers" ] version = "0.30" default-features = false features = [ "resource" ] + +[target.'cfg(unix)'.dependencies] +rlimit = "0.11" diff --git a/cli/build.rs b/cli/build.rs new file mode 100644 index 0000000000..9c799f223c --- /dev/null +++ b/cli/build.rs @@ -0,0 +1,21 @@ +// Copyright (c) 2019-2026 Provable Inc. +// This file is part of the snarkOS library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[path = "../version_env.rs"] +mod version_env; + +fn main() { + version_env::emit_version_env(); +} diff --git a/cli/src/commands/start.rs b/cli/src/commands/start.rs index 290db8d160..4b23e4abd0 100644 --- a/cli/src/commands/start.rs +++ b/cli/src/commands/start.rs @@ -27,7 +27,7 @@ use snarkos_node::{ rest::DEFAULT_REST_PORT, router::DEFAULT_NODE_PORT, }; -use snarkos_utilities::{NodeDataDir, SignalHandler, jwt_secret_file, node_data}; +use snarkos_utilities::{DevHotswapConfig, NodeDataDir, SignalHandler, jwt_secret_file, node_data}; use snarkvm::{ console::{ @@ -339,6 +339,10 @@ impl Start { // Error messages. let node_parse_error = || "Failed to start node"; + // Periodically check if the number of file descriptors isn't becoming insufficient. + #[cfg(unix)] + crate::helpers::spawn_fd_monitor(); + // Clone the configurations. let mut self_ = self.clone(); @@ -853,8 +857,10 @@ impl Start { } }; - // Determine the number of validators for the committee hotswap. - let dev_num_validators_for_committee_hotswap = self.dev_on_prod.then_some(self.dev_num_validators); + // Determine the dev committee hotswap configuration. + let dev_hotswap_config = self.dev_on_prod.then_some(DevHotswapConfig { + dev_num_validators: self.dev_num_validators, + }); // TODO(kaimast): start the display earlier and show sync progress. if !self.nodisplay && cdn.is_some() { @@ -872,8 +878,7 @@ impl Start { // Initialize the node. let node = match node_type { - // NodeType::Validator => Node::new_validator(node_ip, self.bft, rest_ip, self.rest_rps, account, &trusted_peers, &trusted_validators, genesis, cdn, storage_mode, node_data_dir, self.trusted_peers_only, self.auto_db_checkpoints.clone(), dev_txs, self.dev, slipstream_configs, signal_handler.clone()).await, - NodeType::Validator => Node::new_validator(node_ip, self.bft, rest_ip, self.rest_rps, account, &trusted_peers, &trusted_validators, genesis, cdn, storage_mode, node_data_dir, self.trusted_peers_only, self.auto_db_checkpoints.clone(), dev_txs, self.dev, slipstream_configs, dev_num_validators_for_committee_hotswap, signal_handler.clone()).await, + NodeType::Validator => Node::new_validator(node_ip, self.bft, rest_ip, self.rest_rps, account, &trusted_peers, &trusted_validators, genesis, cdn, storage_mode, node_data_dir, self.trusted_peers_only, self.auto_db_checkpoints.clone(), dev_txs, self.dev, slipstream_configs, dev_hotswap_config, signal_handler.clone()).await, NodeType::Prover => Node::new_prover(node_ip, account, &trusted_peers, genesis, node_data_dir, self.trusted_peers_only, self.dev, signal_handler.clone()).await, NodeType::Client => Node::new_client(node_ip, rest_ip, self.rest_rps, account, &trusted_peers, genesis, cdn, storage_mode, node_data_dir, self.trusted_peers_only, self.auto_db_checkpoints.clone(), self.dev, slipstream_configs, signal_handler.clone()).await, NodeType::BootstrapClient => Node::new_bootstrap_client(node_ip, account, *genesis.header(), self.dev).await, diff --git a/cli/src/helpers/args.rs b/cli/src/helpers/args.rs index d98931606c..2263d530d9 100644 --- a/cli/src/helpers/args.rs +++ b/cli/src/helpers/args.rs @@ -42,8 +42,7 @@ pub(crate) fn prepare_endpoint(endpoint: Uri) -> Result { } if parts.path_and_query.is_none() { - // An empty path is fine for the base URL. - parts.path_and_query = Some(uri::PathAndQuery::from_static("")); + parts.path_and_query = Some(uri::PathAndQuery::from_static("/")); } // Given that the input URI is valid and the scheme we assign is valid, this should never fail. diff --git a/cli/src/helpers/fd_check.rs b/cli/src/helpers/fd_check.rs new file mode 100644 index 0000000000..6be577444a --- /dev/null +++ b/cli/src/helpers/fd_check.rs @@ -0,0 +1,197 @@ +// Copyright (c) 2019-2026 Provable Inc. +// This file is part of the snarkOS library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::io; + +use tokio::time::{Duration, MissedTickBehavior, interval}; +use tracing::*; + +/// Node-scale fd use. +#[derive(Debug, Clone, Copy)] +pub struct FdUsage { + /// File descriptors currently open. + pub open: u64, + /// Current soft limit (RLIMIT_NOFILE). `None` == unlimited. + pub soft_limit: Option, +} + +impl FdUsage { + /// Fraction of the soft limit in use (0.0..=1.0). 0.0 when unlimited. + pub fn ratio(&self) -> f64 { + match self.soft_limit { + Some(limit) if limit > 0 => self.open as f64 / limit as f64, + _ => 0.0, + } + } + + /// True once usage reaches `threshold` of the soft limit (e.g. 0.8 == 80%). + pub fn approaching_limit(&self, threshold: f64) -> bool { + self.soft_limit.is_some() && self.ratio() >= threshold + } +} + +/// Probe the live system: current soft limit + count of open descriptors. +pub fn fd_usage() -> io::Result { + let soft_limit = soft_nofile_limit()?; + let open = count_open_fds(soft_limit)?; + Ok(FdUsage { open, soft_limit }) +} + +fn soft_nofile_limit() -> io::Result> { + let (soft, _hard) = rlimit::Resource::NOFILE.get()?; + Ok(if soft == rlimit::INFINITY { None } else { Some(soft) }) +} + +#[cfg(target_os = "linux")] +fn count_open_fds(_limit: Option) -> io::Result { + // Each open descriptor is an entry in /proc/self/fd. The directory + // handle itself holds one fd while we iterate, so subtract it back out. + let mut n: u64 = 0; + for entry in std::fs::read_dir("/proc/self/fd")? { + entry?; + n += 1; + } + Ok(n.saturating_sub(1)) +} + +#[cfg(all(unix, not(target_os = "linux")))] +fn count_open_fds(_limit: Option) -> io::Result { + // macOS and most BSDs expose open fds via /dev/fd (same idea as Linux's /proc/self/fd). + // The directory handle itself holds one fd while we iterate, so subtract it back out. + let mut n: u64 = 0; + for entry in std::fs::read_dir("/dev/fd")? { + entry?; + n += 1; + } + Ok(n.saturating_sub(1)) +} + +/// System-wide (whole machine) fd use. +#[derive(Debug, Clone, Copy)] +pub struct SystemFd { + pub allocated: u64, + pub max: u64, +} + +impl SystemFd { + pub fn ratio(&self) -> f64 { + if self.max > 0 { self.allocated as f64 / self.max as f64 } else { 0.0 } + } +} + +#[cfg(target_os = "linux")] +pub fn system_fd_usage() -> std::io::Result { + // /proc/sys/fs/file-nr => "\t\t" + let s = std::fs::read_to_string("/proc/sys/fs/file-nr")?; + let mut f = s.split_whitespace(); + let bad = || std::io::Error::new(std::io::ErrorKind::InvalidData, "unexpected file-nr format"); + let allocated = f.next().and_then(|v| v.parse().ok()).ok_or_else(bad)?; + let _free = f.next(); // always 0 on modern kernels + let max = f.next().and_then(|v| v.parse().ok()).ok_or_else(bad)?; + Ok(SystemFd { allocated, max }) +} + +#[cfg(all(unix, not(target_os = "linux")))] +pub fn system_fd_usage() -> std::io::Result { + // OID names differ by flavor; values are plain integers. + #[cfg(target_os = "freebsd")] + let (cur_oid, max_oid) = ("kern.openfiles", "kern.maxfiles"); + #[cfg(target_os = "macos")] + let (cur_oid, max_oid) = ("kern.num_files", "kern.maxfiles"); + #[cfg(any(target_os = "openbsd", target_os = "netbsd"))] + let (cur_oid, max_oid) = ("kern.nfiles", "kern.maxfiles"); + #[cfg(not(any(target_os = "freebsd", target_os = "macos", target_os = "openbsd", target_os = "netbsd")))] + return Err(std::io::Error::new(std::io::ErrorKind::Unsupported, "system fd probe unsupported on this OS")); + + fn read(oid: &str) -> std::io::Result { + let out = std::process::Command::new("sysctl").arg("-n").arg(oid).output()?; + if !out.status.success() { + return Err(std::io::Error::new(std::io::ErrorKind::NotFound, format!("sysctl {oid} unavailable"))); + } + String::from_utf8_lossy(&out.stdout) + .trim() + .parse() + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, format!("bad value for {oid}"))) + } + + Ok(SystemFd { allocated: read(cur_oid)?, max: read(max_oid)? }) +} + +pub fn spawn_fd_monitor() { + tokio::spawn(async move { + let mut tick = interval(Duration::from_secs(30)); + tick.set_missed_tick_behavior(MissedTickBehavior::Skip); + + loop { + tick.tick().await; + + // (1) the node's own fds + match fd_usage() { + Ok(u) => { + if let Some(limit) = u.soft_limit { + let (pct, left) = (u.ratio() * 100.0, limit.saturating_sub(u.open)); + if u.ratio() >= 0.95 { + error!( + scope = "process", + open = u.open, + limit, + left, + pct = format!("{pct:.1}%"), + "node fd usage critical" + ); + } else if u.ratio() >= 0.80 { + warn!( + scope = "process", + open = u.open, + limit, + left, + pct = format!("{pct:.1}%"), + "node fd usage elevated" + ); + } + } + } + Err(e) => error!(error = %e, "process fd probe failed"), + } + + // (2) whole-machine fds are allowed 5 percentage points more leeway. + match system_fd_usage() { + Ok(s) => { + let (pct, left) = (s.ratio() * 100.0, s.max.saturating_sub(s.allocated)); + if s.ratio() >= 0.90 { + error!( + scope = "system", + allocated = s.allocated, + max = s.max, + left, + pct = format!("{pct:.1}%"), + "system-wide fd usage critical" + ); + } else if s.ratio() >= 0.75 { + warn!( + scope = "system", + allocated = s.allocated, + max = s.max, + left, + pct = format!("{pct:.1}%"), + "system-wide fd usage elevated" + ); + } + } + Err(e) => error!(error = %e, "system fd probe failed"), + } + } + }); +} diff --git a/cli/src/helpers/mod.rs b/cli/src/helpers/mod.rs index a21aa82f23..c2a7508c8e 100644 --- a/cli/src/helpers/mod.rs +++ b/cli/src/helpers/mod.rs @@ -22,6 +22,11 @@ use log_writer::*; mod dynamic_format; use dynamic_format::*; +#[cfg(target_family = "unix")] +mod fd_check; +#[cfg(target_family = "unix")] +pub use fd_check::*; + pub(crate) mod args; pub mod logger; @@ -47,16 +52,11 @@ pub fn check_open_files_limit(minimum: u64) { Ok((soft_limit, _)) => { // Check if requirements are met. if soft_limit < minimum { - // Warn about too low limit. - let warning = [ - format!("⚠️ The open files limit ({soft_limit}) for this process is lower than recommended."), - format!(" • To ensure correct behavior of the node, please raise it to at least {minimum}."), - " • See the `ulimit` command and `/etc/security/limits.conf` for more details.".to_owned(), - ] - .join("\n") - .yellow() - .bold(); - eprintln!("{warning}\n"); + panic!( + "The open files limit ({soft_limit}) for this process is too low. \ + Please raise it to at least {minimum} \ + See the `ulimit` command and `/etc/security/limits.conf` for more details.", + ); } } Err(err) => { diff --git a/cli/src/helpers/updater.rs b/cli/src/helpers/updater.rs index 40c5434ee4..d10bdf733f 100644 --- a/cli/src/helpers/updater.rs +++ b/cli/src/helpers/updater.rs @@ -47,7 +47,7 @@ impl Updater { .repo_owner(Self::SNARKOS_REPO_OWNER) .repo_name(Self::SNARKOS_REPO_NAME) .bin_name(Self::SNARKOS_BIN_NAME) - .current_version(env!("CARGO_PKG_VERSION")) + .current_version(env!("SNARKOS_VERSION")) .show_download_progress(show_output) .no_confirm(true) .show_output(show_output); @@ -66,7 +66,7 @@ impl Updater { .repo_owner(Self::SNARKOS_REPO_OWNER) .repo_name(Self::SNARKOS_REPO_NAME) .bin_name(Self::SNARKOS_BIN_NAME) - .current_version(env!("CARGO_PKG_VERSION")) + .current_version(env!("SNARKOS_VERSION")) .build()?; let current_version = updater.current_version(); @@ -92,6 +92,23 @@ impl Updater { } } +#[cfg(test)] +mod tests { + use std::{fs, path::Path}; + + #[test] + fn snarkos_version_matches_release_version() { + let release_version = Path::new(env!("CARGO_MANIFEST_DIR")) + .ancestors() + .map(|dir| dir.join(".cargo").join("release-version")) + .find(|path| path.is_file()) + .map(|path| fs::read_to_string(path).unwrap()) + .unwrap(); + + assert_eq!(env!("SNARKOS_VERSION"), release_version.trim().trim_start_matches('v')); + } +} + #[derive(Debug, Error)] pub enum UpdaterError { #[error("{}: {}", _0, _1)] diff --git a/display/Cargo.toml b/display/Cargo.toml index 13bb57989a..ed6adde7eb 100644 --- a/display/Cargo.toml +++ b/display/Cargo.toml @@ -29,6 +29,8 @@ workspace = true [dependencies.ratatui] version = "0.30" +default-features = false +features = ["crossterm", "layout-cache", "macros", "underline-color"] [dependencies.snarkos-node] workspace = true diff --git a/node/Cargo.toml b/node/Cargo.toml index 70bc26a413..d44050c4e8 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -71,6 +71,9 @@ workspace = true [dependencies.bytes] workspace = true +[dependencies.cfg-if] +workspace = true + [dependencies.colored] workspace = true diff --git a/node/bft/ledger-service/Cargo.toml b/node/bft/ledger-service/Cargo.toml index 265cf5f785..f5b3f6b22b 100644 --- a/node/bft/ledger-service/Cargo.toml +++ b/node/bft/ledger-service/Cargo.toml @@ -18,7 +18,7 @@ edition = "2024" [features] default = [ ] -ledger = [ "parking_lot", "rand", "rand_chacha", "rayon", "tokio", "tracing" ] +ledger = [ "parking_lot", "rand", "rayon", "tokio", "tracing" ] ledger-write = [ ] locktick = [ "dep:locktick", @@ -33,7 +33,7 @@ serial = [ "snarkvm/serial" ] test = [ "mock", "translucent" ] -test_network = [ ] +test_network = [ "snarkvm/dev-committee" ] translucent = [ "ledger" ] [dependencies.anyhow] @@ -66,10 +66,6 @@ optional = true workspace = true optional = true -[dependencies.rand_chacha] -workspace = true -optional = true - [dependencies.rayon] workspace = true optional = true diff --git a/node/bft/ledger-service/src/ledger.rs b/node/bft/ledger-service/src/ledger.rs index 7e2ee227a1..7d3d3ec136 100644 --- a/node/bft/ledger-service/src/ledger.rs +++ b/node/bft/ledger-service/src/ledger.rs @@ -15,10 +15,12 @@ use crate::{BeginLedgerUpdateError, LedgerService, LedgerUpdateService, fmt_id, spawn_blocking}; -#[cfg(feature = "test_network")] -use snarkos_utilities::NodeDataDir; use snarkos_utilities::Stoppable; +#[cfg(feature = "test_network")] +use snarkos_utilities::{DevHotswapConfig, NodeDataDir}; +#[cfg(feature = "test_network")] +use snarkvm::ledger::DevCommitteeOptions; use snarkvm::{ ledger::{ Block, @@ -70,8 +72,6 @@ pub struct CoreLedgerService> { latest_leader: Arc)>>>, stoppable: Arc, update_lock: Arc>, - #[cfg(feature = "test_network")] - dev_committee: Option>, } /// A transactional update to the ledger. @@ -142,125 +142,14 @@ impl> CoreLedgerService { #[cfg(feature = "metrics")] metrics::gauge(metrics::bft::HEIGHT, ledger.latest_block().height() as f64); - Self::new_inner(ledger, stoppable, None) - } - - /// Initializes a new core ledger service that persists hotswapped dev committee state to disk. - /// - /// This variant should be used by long-running nodes (e.g. validators) that may be restarted, - /// so that the deterministic dev committee's starting round remains stable across runs. - #[cfg(feature = "test_network")] - pub fn new_dev( - ledger: Ledger, - stoppable: Arc, - dev_committee_config: Option<(NodeDataDir, u16)>, - ) -> Self { - // Initialize the block height metric. - #[cfg(feature = "metrics")] - metrics::gauge(metrics::bft::HEIGHT, ledger.latest_block().height() as f64); - // Build the deterministic dev committee. - let dev_committee = dev_committee_config.map(|(node_data_dir, dev_num_validators)| { - Self::build_dev_committee(ledger.latest_round(), node_data_dir, dev_num_validators) - .expect("Failed to build dev committee") - }); - Self::new_inner(ledger, stoppable, dev_committee) - } - - /// Initializes the core ledger service. - fn new_inner(ledger: Ledger, stoppable: Arc, _dev_committee: Option>) -> Self { - Self { - ledger, - latest_leader: Default::default(), - stoppable, - update_lock: Default::default(), - #[cfg(feature = "test_network")] - dev_committee: _dev_committee, - } - } - - /// Builds the deterministic dev committee with `dev_num_validators` members, if requested. - /// - /// Returns `Ok(None)` when `dev_num_validators` is `None`, otherwise returns a committee - /// whose starting round is anchored to the round at which the dev committee was first - /// activated. - /// - /// The starting round is persisted to disk on first activation and re-read - /// on subsequent invocations. This keeps the committee's identity (and - /// therefore the certificates that reference it) consistent across - /// restarts. - #[cfg(feature = "test_network")] - fn build_dev_committee( - default_start_round: u64, - node_data_dir: NodeDataDir, - dev_num_validators: u16, - ) -> Result> { - let start_round = Self::load_or_init_dev_committee_start_round(node_data_dir, default_start_round)?; - - use rand::SeedableRng; - let mut rng = rand_chacha::ChaChaRng::seed_from_u64(snarkos_utilities::DEVELOPMENT_MODE_RNG_SEED); - let dev_keys = (0..dev_num_validators) - .map(|_| snarkvm::console::account::PrivateKey::::new(&mut rng)) - .collect::>>()?; - let members = dev_keys - .iter() - .map(Address::::try_from) - .collect::>>()? - .into_iter() - .map(|address| (address, (snarkvm::ledger::committee::MIN_VALIDATOR_STAKE, true, 0))) - .collect::>(); - Committee::new(start_round, members) - } - - /// Reads the persisted dev committee starting round from disk if it exists and is consistent - /// with `default_start_round`; otherwise writes the default to disk and returns it. - #[cfg(feature = "test_network")] - fn load_or_init_dev_committee_start_round(node_data_dir: NodeDataDir, default_start_round: u64) -> Result { - let path = node_data_dir.dev_committee_state_path(); - let path_str = path.display(); - // If the dev committee state file exists, read it and parse the starting round. - if path.exists() { - let contents = std::fs::read_to_string(&path) - .map_err(|err| anyhow::anyhow!("Failed to read dev committee state from {path_str} - {err}"))?; - let start_round = contents.trim().parse::().map_err(|err| { - anyhow::anyhow!("Failed to parse dev committee state at {path_str} ({contents}) - {err}",) - })?; - - if start_round > default_start_round { - bail!( - "Stale dev committee starting round {start_round} at {path_str} (current ledger round is {default_start_round})" - ); - } - - tracing::info!("Loaded the dev committee starting round {start_round} from {path_str}"); - Ok(start_round) - // If the dev committee state file does not exist, write the default starting round to it. - } else { - Self::write_dev_committee_start_round(&path, default_start_round)?; - tracing::info!("Persisted the dev committee starting round {default_start_round} to {path_str}"); - Ok(default_start_round) - } - } - - /// Writes the given `start_round` to the dev committee state file at `path`, creating the - /// parent directory if needed. - #[cfg(feature = "test_network")] - fn write_dev_committee_start_round(path: &std::path::Path, start_round: u64) -> Result<()> { - if let Some(parent) = path.parent() - && !parent.exists() - { - std::fs::create_dir_all(parent).map_err(|err| { - anyhow::anyhow!("Failed to create dev committee state directory {} - {err}", parent.display()) - })?; - } - std::fs::write(path, start_round.to_string()) - .map_err(|err| anyhow::anyhow!("Failed to write dev committee state to {} - {err}", path.display()))?; - Ok(()) + Self { ledger, latest_leader: Default::default(), stoppable, update_lock: Default::default() } } - /// Returns the deterministic dev committee for rounds at or after the hotswap start. + /// Returns the deterministic dev committee for rounds at or after the hotswap start, + /// reading from the snarkVM `Ledger` (which owns the committee under `--dev-on-prod`). #[cfg(feature = "test_network")] fn dev_committee_for_round(&self, round: u64) -> Result>> { - let Some(dev_committee) = self.dev_committee.as_ref() else { + let Some(dev_committee) = self.ledger.dev_committee() else { return Ok(None); }; if round < dev_committee.starting_round() { @@ -270,6 +159,68 @@ impl> CoreLedgerService { } } +/// Resolves the dev committee's starting round prior to loading the ledger. +/// +/// Resolution order (highest priority first): +/// 1. The round persisted to `/dev-committee-state` from a previous run. +/// 2. `None` — defer to snarkVM, which falls back to the latest block's round at load time +/// and is then persisted by [`persist_dev_committee_start_round_if_unwritten`]. +#[cfg(feature = "test_network")] +pub fn prepare_dev_committee_options( + node_data_dir: &NodeDataDir, + config: DevHotswapConfig, +) -> Result { + let path = node_data_dir.dev_committee_state_path(); + let path_str = path.display(); + + let start_round = if path.exists() { + let contents = std::fs::read_to_string(&path) + .map_err(|err| anyhow::anyhow!("Failed to read dev committee state from {path_str} - {err}"))?; + let r = contents.trim().parse::().map_err(|err| { + anyhow::anyhow!("Failed to parse dev committee state at {path_str} ({contents}) - {err}",) + })?; + tracing::info!("Loaded the dev committee starting round {r} from {path_str}"); + Some(r) + } else { + None + }; + + Ok(DevCommitteeOptions { + start_round, + dev_num_validators: config.dev_num_validators, + seed: snarkos_utilities::DEVELOPMENT_MODE_RNG_SEED, + }) +} + +/// Persists the given `start_round` to `/dev-committee-state` if the file +/// doesn't already exist. Called after [`Ledger::load_with_dev_committee`] so that the +/// round chosen by snarkVM (its `latest_round()` default) survives restarts. +#[cfg(feature = "test_network")] +pub fn persist_dev_committee_start_round_if_unwritten(node_data_dir: &NodeDataDir, start_round: u64) -> Result<()> { + let path = node_data_dir.dev_committee_state_path(); + if !path.exists() { + write_dev_committee_start_round(&path, start_round)?; + tracing::info!("Persisted the dev committee starting round {start_round} to {}", path.display()); + } + Ok(()) +} + +/// Writes the given `start_round` to the dev committee state file at `path`, creating the +/// parent directory if needed. +#[cfg(feature = "test_network")] +fn write_dev_committee_start_round(path: &std::path::Path, start_round: u64) -> Result<()> { + if let Some(parent) = path.parent() + && !parent.exists() + { + std::fs::create_dir_all(parent).map_err(|err| { + anyhow::anyhow!("Failed to create dev committee state directory {} - {err}", parent.display()) + })?; + } + std::fs::write(path, start_round.to_string()) + .map_err(|err| anyhow::anyhow!("Failed to write dev committee state to {} - {err}", path.display()))?; + Ok(()) +} + impl> fmt::Debug for CoreLedgerService { /// Implements a custom `fmt::Debug` for `CoreLedgerService`. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -363,7 +314,7 @@ impl> LedgerService for CoreLedgerService< fn current_committee(&self) -> Result> { #[cfg(feature = "test_network")] { - if let Some(dev_committee) = self.dev_committee.as_ref() { + if let Some(dev_committee) = self.ledger.dev_committee() { return Ok(dev_committee.clone()); } } @@ -595,7 +546,7 @@ impl> LedgerService for CoreLedgerService< match transaction { Transaction::Deploy(_, _, _, deployment, _) => { let (_, cost_details) = deployment_cost(self.ledger.vm().process(), deployment, consensus_version)?; - let compute_spend = deploy_compute_cost_in_microcredits(cost_details, consensus_version)?; + let compute_spend = deploy_compute_cost_in_microcredits(cost_details, consensus_version); ensure!( compute_spend <= transaction_spend_limit, "Transaction '{id}' exceeds the transaction spend limit with compute_spend: '{compute_spend}'" @@ -604,7 +555,7 @@ impl> LedgerService for CoreLedgerService< } Transaction::Execute(_, _, execution, _) => { let (_, cost_details) = execution_cost(self.ledger.vm().process(), execution, consensus_version)?; - let compute_spend = execute_compute_cost_in_microcredits(cost_details, consensus_version)?; + let compute_spend = execute_compute_cost_in_microcredits(cost_details, consensus_version); if consensus_version >= ConsensusVersion::V11 { // From V11, add this check for consistency with our deployment checks. ensure!( diff --git a/node/bft/src/gateway.rs b/node/bft/src/gateway.rs index 251318258f..9ba9a0fc24 100644 --- a/node/bft/src/gateway.rs +++ b/node/bft/src/gateway.rs @@ -61,6 +61,7 @@ use snarkos_node_tcp::{ ConnectionSide, P2P, Tcp, + connections::DisconnectOrigin, protocols::{Disconnect, Handshake, OnConnect, Reading, Writing}, }; use snarkos_utilities::NodeDataDir; @@ -1377,7 +1378,9 @@ impl Writing for Gateway { #[async_trait] impl Disconnect for Gateway { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin) { + debug!("Physically disconnecting from {peer_addr}; origin: {origin:?}"); + if let Some(peer_ip) = self.resolve_to_listener(&peer_addr) { // TODO(kaimast): This can, in theory, still lead to race conditions, if we immediately reconnect to the same peer. // In practice, there should always be a significant delay between those two delays, so it is not an immediate issue. diff --git a/node/cdn/build.rs b/node/cdn/build.rs new file mode 100644 index 0000000000..e0ab0243cc --- /dev/null +++ b/node/cdn/build.rs @@ -0,0 +1,21 @@ +// Copyright (c) 2019-2026 Provable Inc. +// This file is part of the snarkOS library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#[path = "../../version_env.rs"] +mod version_env; + +fn main() { + version_env::emit_version_env(); +} diff --git a/node/cdn/src/blocks.rs b/node/cdn/src/blocks.rs index fab03377b9..2815a542ea 100644 --- a/node/cdn/src/blocks.rs +++ b/node/cdn/src/blocks.rs @@ -57,7 +57,7 @@ pub const CDN_BASE_URL: &str = "https://cdn.provable.com/v0/blocks"; /// Returns the user-agent string for CDN requests. const fn cdn_user_agent() -> &'static str { - concat!("snarkos/", env!("CARGO_PKG_VERSION")) + concat!("snarkos/", env!("SNARKOS_VERSION")) } /// Updates the metrics during CDN sync. diff --git a/node/consensus/src/lib.rs b/node/consensus/src/lib.rs index f32fadf3a5..a4150c57df 100644 --- a/node/consensus/src/lib.rs +++ b/node/consensus/src/lib.rs @@ -31,6 +31,8 @@ use snarkos_node_bft::{ Primary, helpers::{ ConsensusReceiver, + ConsensusSender, + PrimaryReceiver, PrimarySender, Storage as NarwhalStorage, fmt_id, @@ -56,7 +58,7 @@ use snarkvm::{ }; use aleo_std::StorageMode; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use cfg_if::cfg_if; use colored::Colorize; use indexmap::IndexMap; @@ -87,6 +89,8 @@ const CAPACITY_FOR_SOLUTIONS: usize = 1 << 10; /// Note: This is an inbound queue limit, not a Narwhal-enforced limit. const MAX_DEPLOYMENTS_PER_INTERVAL: usize = 1; +type BftRunArgs = Arc, PrimaryReceiver)>>>; + /// Wrapper around `BFT` that adds additional functionality, such as a mempool. /// /// Consensus acts as a rate limiter to prevents workers in BFT from being overloaded. @@ -119,10 +123,14 @@ pub struct Consensus { block_sync: Arc>, /// Notifies when a block is committed, and relays it to the primary. block_commit_notify: Arc, + /// Holds the consensus receiver until [`Self::start_consensus_handlers`] is called. + consensus_receiver: Arc>>>, + /// Holds the arguments for `BFT::run` until [`Self::start_consensus_handlers`] is called. + bft_run_args: BftRunArgs, } impl Consensus { - /// Initializes a new instance of consensus and spawn its background tasks. + /// Initializes a new instance of consensus. #[allow(clippy::too_many_arguments)] pub async fn new( account: Account, @@ -155,8 +163,11 @@ impl Consensus { node_data_dir, dev, )?; + // Initialize the consensus channels. + let (consensus_sender, consensus_receiver) = init_consensus_channels(); + // Create a new instance of Consensus. - let mut _self = Self { + let _self = Self { ledger, bft, block_sync, @@ -170,17 +181,10 @@ impl Consensus { handles: Default::default(), ping: ping.clone(), block_commit_notify: Arc::new(Notify::new()), + consensus_receiver: Arc::new(Mutex::new(Some(consensus_receiver))), + bft_run_args: Arc::new(Mutex::new(Some((consensus_sender, primary_receiver)))), }; - info!("Starting the consensus instance..."); - - // First, initialize the consensus channels. - let (consensus_sender, consensus_receiver) = init_consensus_channels(); - // Then, start the consensus handlers. - _self.start_handlers(consensus_receiver); - // Lastly, also start BFTs handlers. - _self.bft.run(Some(ping), Some(consensus_sender), _self.primary_sender.clone(), primary_receiver).await?; - Ok(_self) } @@ -492,10 +496,27 @@ impl Consensus { } impl Consensus { - /// Starts the consensus handlers. + /// Starts the BFT and consensus handlers. /// - /// This is only invoked once, in the constructor. - fn start_handlers(&self, consensus_receiver: ConsensusReceiver) { + /// This consumes the deferred state stored during construction and must only be invoked once, + /// after the node has finished syncing from the CDN, so that no blocks are committed during + /// the initial sync. + pub async fn start_consensus_handlers(&self) -> Result<()> { + info!("Starting the consensus instance..."); + + // Take the BFT run arguments stored during construction and start the BFT handlers. + let Some((consensus_sender, primary_receiver)) = self.bft_run_args.lock().take() else { + bail!("The consensus handlers have already been started"); + }; + self.bft + .clone() + .run(Some(self.ping.clone()), Some(consensus_sender), self.primary_sender.clone(), primary_receiver) + .await?; + + // Take the consensus receiver stored during construction and start the consensus handlers. + let Some(consensus_receiver) = self.consensus_receiver.lock().take() else { + bail!("The consensus handlers have already been started"); + }; let ConsensusReceiver { mut rx_consensus_subdag } = consensus_receiver; // Process the committed subdag and transmissions from the BFT. @@ -531,6 +552,8 @@ impl Consensus { } } }); + + Ok(()) } /// Attempts to build a new block from the given subDAG, and (tries to) advance the legder to it. diff --git a/node/metrics/build.rs b/node/metrics/build.rs index af0e5b4f0c..9fcc289052 100644 --- a/node/metrics/build.rs +++ b/node/metrics/build.rs @@ -13,6 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[path = "../../version_env.rs"] +mod version_env; + fn main() { + version_env::emit_version_env(); built::write_built_file().expect("Failed to acquire build-time information"); } diff --git a/node/metrics/src/lib.rs b/node/metrics/src/lib.rs index 7e867dc8e3..2dc7ab230a 100644 --- a/node/metrics/src/lib.rs +++ b/node/metrics/src/lib.rs @@ -177,7 +177,7 @@ mod built_info { /// The resulting metric will show as: /// snarkos_build_info{version="4.2.1",git_commit="abc123",git_branch="main",features="cuda,metrics"} 1 pub fn set_build_info() { - let version = built_info::PKG_VERSION; + let version = env!("SNARKOS_VERSION"); let git_commit = built_info::GIT_COMMIT_HASH.unwrap_or("unknown"); let git_branch = built_info::GIT_HEAD_REF.unwrap_or("unknown"); let features = built_info::FEATURES_LOWERCASE_STR.replace(' ', ""); diff --git a/node/network/src/peer.rs b/node/network/src/peer.rs index 1c322d6f42..98a3185fab 100644 --- a/node/network/src/peer.rs +++ b/node/network/src/peer.rs @@ -133,7 +133,11 @@ impl Peer { // Logic check: this can only happen during the handshake. This isn't a fatal // error, but should not be triggered. if !matches!(self, Self::Connecting(_)) { - warn!("Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting"); + warn!( + "Peer '{listener_addr}' is being upgraded to Connected, but isn't Connecting \ + - it is {}", + if self.is_connected() { "already Connected" } else { "only a Candidate" } + ); } *self = Self::Connected(ConnectedPeer { diff --git a/node/rest/build.rs b/node/rest/build.rs index af0e5b4f0c..9fcc289052 100644 --- a/node/rest/build.rs +++ b/node/rest/build.rs @@ -13,6 +13,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[path = "../../version_env.rs"] +mod version_env; + fn main() { + version_env::emit_version_env(); built::write_built_file().expect("Failed to acquire build-time information"); } diff --git a/node/rest/src/lib.rs b/node/rest/src/lib.rs index 4081d5c1b8..9c8db109ee 100644 --- a/node/rest/src/lib.rs +++ b/node/rest/src/lib.rs @@ -211,6 +211,7 @@ impl, R: Routing> Rest { .route("/transaction/{id}", get(Self::get_transaction)) .route("/transaction/confirmed/{id}", get(Self::get_confirmed_transaction)) .route("/transaction/unconfirmed/{id}", get(Self::get_unconfirmed_transaction)) + .route("/transaction/rejected/{id}/reason", get(Self::get_transaction_rejection_reason)) .route("/transaction/broadcast", post(Self::transaction_broadcast)) // GET and POST ../solution/.. @@ -282,11 +283,15 @@ impl, R: Routing> Rest { None => routes, }; - // If the `history` feature is enabled, enable the additional endpoint. + // Register the view-at-latest-height endpoint (always available, no history required). + let routes = routes.route("/program/{id}/view/{function}", post(Self::evaluate_view_latest)); + + // If the `history` feature is enabled, enable the additional endpoints. #[cfg(feature = "history")] let routes = routes .route("/program/{id}/mapping/{name}/{key}/history/{height}", get(Self::get_history)) - .route("/program/{id}/mapping/{name}/history/{height}", get(Self::get_history_batch)); + .route("/program/{id}/mapping/{name}/history/{height}", get(Self::get_history_batch)) + .route("/program/{id}/view/{function}/{height}", post(Self::evaluate_view)); // If the `history-staking-rewards` feature is enabled, enable the additional endpoint. #[cfg(feature = "history-staking-rewards")] @@ -318,8 +323,8 @@ impl, R: Routing> Rest { routes // Pass in `Rest` to make things convenient. .with_state(self.clone()) - // Cap the request body size at 512KiB. - .layer(DefaultBodyLimit::max(512 * 1024)) + // Cap the request body size at 1.5MiB. + .layer(DefaultBodyLimit::max(2 * 768 * 1024)) .layer(GovernorLayer { config: governor_config.into(), }) diff --git a/node/rest/src/routes.rs b/node/rest/src/routes.rs index 42e55455de..f35735de60 100644 --- a/node/rest/src/routes.rs +++ b/node/rest/src/routes.rs @@ -21,7 +21,18 @@ use snarkos_node_sync::BftSyncMode; use snarkvm::ledger::store::helpers::MapRead; use snarkvm::{ ledger::puzzle::Solution, - prelude::{Address, Identifier, LimitedWriter, Plaintext, Program, ToBytes, block::Transaction}, + prelude::{ + Address, + ConsensusVersion, + Identifier, + LimitedWriter, + Plaintext, + Program, + ToBytes, + Value, + block::Transaction, + }, + synthesizer::program::{FinalizeGlobalState, StackTrait}, }; use axum::{Json, extract::rejection::JsonRejection}; @@ -44,6 +55,8 @@ const MAX_KEYS_PER_REQUEST: usize = 1 << 7; type HistoricalMappingKey = (ProgramID, Identifier, Plaintext, u32); #[cfg(feature = "history")] type HistoricalMappingRoute = (ProgramID, Identifier, u32); +#[cfg(feature = "history")] +type ViewFunctionRoute = (ProgramID, Identifier, u32); #[cfg(feature = "history")] fn parse_historical_mapping_keys(keys: &[String]) -> Result>, RestError> { @@ -71,6 +84,19 @@ fn parse_historical_mapping_keys(keys: &[String]) -> Result, _>>() } +/// Parses a list of strings into a `Vec>` for use as view function inputs. +fn parse_view_inputs(inputs: &[String]) -> Result>, RestError> { + inputs + .iter() + .enumerate() + .map(|(index, input)| { + input.parse::>().map_err(|err| { + RestError::unprocessable_entity(err.context(format!("Invalid input at index {index}: {input}"))) + }) + }) + .collect::, _>>() +} + /// Deserialize a CSV string into a vector of strings. fn de_csv<'de, D>(de: D) -> std::result::Result, D::Error> where @@ -417,6 +443,49 @@ impl, R: Routing> Rest { })?)) } + /// GET //transaction/rejected/{transactionID}/reason + pub(crate) async fn get_transaction_rejection_reason( + State(rest): State, + Path(tx_id): Path, + ) -> Result { + let rejection_reason = Self::lookup_transaction_rejection_reason(&rest, &tx_id)?; + match rejection_reason { + Some(reason) => Ok(ErasedJson::pretty(reason)), + None => Err(RestError::not_found(anyhow!("Rejection reason not found for transaction {tx_id}"))), + } + } + + /// Looks up the rejection reason for a transaction ID. + /// + /// Rejection reasons are stored under the confirmed (fee) transaction ID. Callers may provide + /// either the unconfirmed transaction ID or the confirmed rejected transaction ID. + fn lookup_transaction_rejection_reason( + rest: &Self, + tx_id: &N::TransactionID, + ) -> Result>, RestError> { + let store = rest.ledger.vm().finalize_store(); + + if let Some(reason) = store.get_rejected_reason(tx_id)? { + return Ok(Some(reason)); + } + + // Fall back to the unconfirmed transaction ID. + if let Some(unconfirmed) = rest.ledger.try_get_unconfirmed_transaction(tx_id)? { + if let Some(reason) = store.get_rejected_reason(&*unconfirmed.id())? { + return Ok(Some(reason)); + } + } + + // Fall back to the confirmed (fee) transaction ID. + if let Some(confirmed) = rest.ledger.try_get_confirmed_transaction(tx_id)? { + if let Some(reason) = store.get_rejected_reason(&*confirmed.id())? { + return Ok(Some(reason)); + } + } + + Ok(None) + } + /// GET //memoryPool/transmissions pub(crate) async fn get_memory_pool_transmissions(State(rest): State) -> Result { match rest.consensus { @@ -1134,6 +1203,134 @@ impl, R: Routing> Rest { Ok((StatusCode::OK, ErasedJson::pretty(values))) } + /// POST /{network}/program/{id}/view/{functionName}/{height} + /// + /// Evaluates a view function against the ledger state at the given block `height`. + /// The request body must be a JSON array of string-encoded inputs, e.g.: + /// + /// ```json + /// ["aleo1...", "10u64"] + /// ``` + /// + /// Returns the outputs as a JSON array of string-encoded values. + #[cfg(feature = "history")] + pub(crate) async fn evaluate_view( + State(rest): State, + Path((program_id, view_name, height)): Path>, + json_result: Result>, JsonRejection>, + ) -> Result { + // Parse the inputs from the request body. + let Json(raw_inputs) = match json_result { + Ok(json) => json, + Err(err) => return Err(RestError::unprocessable_entity(anyhow!("Invalid request body: {err}"))), + }; + + // Parse the inputs into `Value`. + let inputs = parse_view_inputs::(&raw_inputs)?; + + // Evaluate the view function in a blocking task. + let outputs = match tokio::task::spawn_blocking(move || { + rest.ledger.vm().evaluate_view_at_height(program_id, view_name, inputs, height) + }) + .await + { + Ok(Ok(outputs)) => outputs, + Ok(Err(err)) => { + return Err(RestError::bad_request( + err.context(format!("Failed to evaluate view '{view_name}' for '{program_id}' at height {height}")), + )); + } + Err(err) => return Err(RestError::internal_server_error(anyhow!("Tokio error: {err}"))), + }; + + // Encode each output as a string. + let output_strings: Vec = outputs.iter().map(|v| v.to_string()).collect(); + + Ok((StatusCode::OK, ErasedJson::pretty(output_strings))) + } + + /// POST /{network}/program/{id}/view/{functionName} + /// + /// Evaluates a view function against the ledger state at the latest block height. + /// The request body must be a JSON array of string-encoded inputs, e.g.: + /// + /// ```json + /// ["aleo1...", "10u64"] + /// ``` + /// + /// Returns the outputs as a JSON array of string-encoded values. + /// Optionally, append `?metadata=true` to also return the block height at which the + /// view was evaluated (same semantics as the mapping-read endpoints). + pub(crate) async fn evaluate_view_latest( + State(rest): State, + Path((program_id, view_name)): Path<(ProgramID, Identifier)>, + metadata: Query, + json_result: Result>, JsonRejection>, + ) -> Result { + // Parse the inputs from the request body. + let Json(raw_inputs) = match json_result { + Ok(json) => json, + Err(err) => return Err(RestError::unprocessable_entity(anyhow!("Invalid request body: {err}"))), + }; + + // Parse the inputs into `Value`. + let inputs = parse_view_inputs::(&raw_inputs)?; + + // Evaluate the view function in a blocking task. + // The latest block's state is captured inside the task to minimise the window + // between state sampling and evaluation. + let (outputs, height) = match tokio::task::spawn_blocking(move || { + // Capture the latest block to build a consistent `FinalizeGlobalState`. + let block = rest.ledger.latest_block(); + let height = block.height(); + + // Reconstruct the `FinalizeGlobalState` for the latest block. The block timestamp + // is only included from `ConsensusVersion::V12` onward, matching the consensus path. + let block_timestamp = + (height >= N::CONSENSUS_HEIGHT(ConsensusVersion::V12).unwrap_or_default()).then_some(block.timestamp()); + let state = FinalizeGlobalState::new::( + block.round(), + height, + block_timestamp, + block.cumulative_weight(), + block.cumulative_proof_target(), + block.previous_hash(), + None, + )?; + + // Get the current (latest-edition) stack for the program. + let stack = rest.ledger.vm().process().get_stack(program_id)?; + + // Evaluate the view against the current finalize store. + let outputs = stack.evaluate_view(state, rest.ledger.vm().finalize_store(), &view_name, inputs)?; + + Ok::<_, anyhow::Error>((outputs, height)) + }) + .await + { + Ok(Ok(result)) => result, + Ok(Err(err)) => { + return Err(RestError::bad_request(err.context(format!( + "Failed to evaluate view '{view_name}' for '{program_id}' at the latest height" + )))); + } + Err(err) => return Err(RestError::internal_server_error(anyhow!("Tokio error: {err}"))), + }; + + // Encode each output as a string. + let output_strings: Vec = outputs.iter().map(|v| v.to_string()).collect(); + + // Check if metadata is requested and return the outputs with the sampled height if so. + if metadata.metadata.unwrap_or(false) { + return Ok(ErasedJson::pretty(json!({ + "data": output_strings, + "height": height, + }))); + } + + Ok(ErasedJson::pretty(output_strings)) + } + /// GET /{network}/staking/rewards/{address}/{height} #[cfg(feature = "history-staking-rewards")] pub(crate) async fn get_staking_reward( diff --git a/node/rest/src/version.rs b/node/rest/src/version.rs index 99a1c943e2..149fe018e2 100644 --- a/node/rest/src/version.rs +++ b/node/rest/src/version.rs @@ -50,7 +50,7 @@ impl VersionInfo { let consensus_heights: Vec = N::CONSENSUS_VERSION_HEIGHTS().iter().map(|(_, height)| *height).collect(); VERSION_INFO.get_or_init(|| VersionInfo { - version: built_info::PKG_VERSION.to_string(), + version: env!("SNARKOS_VERSION").to_string(), git_commit: built_info::GIT_COMMIT_HASH.unwrap_or("unknown").to_string(), git_branch: built_info::GIT_HEAD_REF.unwrap_or("unknown").to_string(), latest_consensus_version: latest_num, diff --git a/node/router/messages/src/lib.rs b/node/router/messages/src/lib.rs index 7376a76a47..7f3f1e7893 100644 --- a/node/router/messages/src/lib.rs +++ b/node/router/messages/src/lib.rs @@ -108,7 +108,7 @@ impl From for Message { impl Message { /// The version of the network protocol; this is incremented for breaking changes between migration versions. // Note. This should be incremented for each new `ConsensusVersion` that is added. - pub const VERSIONS: [(ConsensusVersion, u32); 10] = [ + pub const VERSIONS: [(ConsensusVersion, u32); 12] = [ (ConsensusVersion::V5, 17), (ConsensusVersion::V7, 18), (ConsensusVersion::V8, 19), @@ -119,6 +119,8 @@ impl Message { (ConsensusVersion::V13, 24), (ConsensusVersion::V14, 25), (ConsensusVersion::V15, 26), + (ConsensusVersion::V16, 27), + (ConsensusVersion::V17, 28), ]; /// Returns the latest message version. diff --git a/node/router/tests/common/router.rs b/node/router/tests/common/router.rs index 0b88d01548..294d5ab5fd 100644 --- a/node/router/tests/common/router.rs +++ b/node/router/tests/common/router.rs @@ -38,6 +38,7 @@ use snarkos_node_tcp::{ ConnectionSide, P2P, Tcp, + connections::DisconnectOrigin, protocols::{Disconnect, Handshake, OnConnect, Reading, Writing}, }; use snarkvm::{ @@ -133,7 +134,7 @@ impl OnConnect for TestRouter { #[async_trait] impl Disconnect for TestRouter { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, _origin: DisconnectOrigin) { if let Some(peer_ip) = self.router().resolve_to_listener(peer_addr) { self.router().downgrade_peer_to_candidate(peer_ip); } diff --git a/node/src/bootstrap_client/network.rs b/node/src/bootstrap_client/network.rs index f8ebc01cc4..d610b11a59 100644 --- a/node/src/bootstrap_client/network.rs +++ b/node/src/bootstrap_client/network.rs @@ -25,7 +25,7 @@ use crate::{ MAX_PEERS_TO_SEND, messages::{self, Message}, }, - tcp::{ConnectionSide, P2P, Tcp, protocols::*}, + tcp::{ConnectionSide, P2P, Tcp, connections::DisconnectOrigin, protocols::*}, }; use snarkvm::prelude::Network; @@ -101,7 +101,9 @@ impl OnConnect for BootstrapClient { #[async_trait] impl Disconnect for BootstrapClient { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin) { + debug!("Physically disconnecting from {peer_addr}; origin: {origin:?}"); + if let Some(listener_addr) = self.resolve_to_listener(peer_addr) { self.downgrade_peer_to_candidate(listener_addr); } diff --git a/node/src/client/router.rs b/node/src/client/router.rs index a97537c5be..c9611a5407 100644 --- a/node/src/client/router.rs +++ b/node/src/client/router.rs @@ -30,7 +30,7 @@ use snarkos_node_router::{ UnconfirmedTransaction, }, }; -use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp}; +use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp, connections::DisconnectOrigin}; use snarkvm::{ console::network::{ConsensusVersion, Network}, ledger::{block::Transaction, narwhal::Data}, @@ -86,7 +86,9 @@ impl> OnConnect for Client { #[async_trait] impl> Disconnect for Client { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin) { + debug!("Physically disconnecting from {peer_addr}; origin: {origin:?}"); + if let Some(peer_ip) = self.router.resolve_to_listener(peer_addr) { let was_fully_connected = self.router.downgrade_peer_to_candidate(peer_ip); diff --git a/node/src/node.rs b/node/src/node.rs index b5c74cd576..29391a7c3f 100644 --- a/node/src/node.rs +++ b/node/src/node.rs @@ -24,7 +24,7 @@ use crate::{ }; use snarkos_account::Account; -use snarkos_utilities::{NodeDataDir, SignalHandler}; +use snarkos_utilities::{DevHotswapConfig, NodeDataDir, SignalHandler}; use snarkvm::prelude::{ Address, @@ -99,7 +99,7 @@ impl Node { dev_txs: bool, dev: Option, slipstream_configs: &[PathBuf], - dev_num_validators_for_committee_hotswap: Option, + dev_hotswap_config: Option, signal_handler: Arc, ) -> Result { let validator = Arc::new( @@ -119,7 +119,7 @@ impl Node { dev_txs, dev, slipstream_configs, - dev_num_validators_for_committee_hotswap, + dev_hotswap_config, signal_handler, ) .await?, diff --git a/node/src/prover/router.rs b/node/src/prover/router.rs index 3c9aa8329f..ecb93e3305 100644 --- a/node/src/prover/router.rs +++ b/node/src/prover/router.rs @@ -26,7 +26,7 @@ use snarkos_node_router::messages::{ PuzzleRequest, UnconfirmedTransaction, }; -use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp}; +use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp, connections::DisconnectOrigin}; use snarkvm::{ console::network::{ConsensusVersion, Network}, ledger::block::Transaction, @@ -85,7 +85,9 @@ where #[async_trait] impl> Disconnect for Prover { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin) { + debug!("Physically disconnecting from {peer_addr}; origin: {origin:?}"); + if let Some(peer_ip) = self.router.resolve_to_listener(peer_addr) { let was_fully_connected = self.router.downgrade_peer_to_candidate(peer_ip); // Only remove the peer from sync if the handshake was successful. diff --git a/node/src/validator/mod.rs b/node/src/validator/mod.rs index c6714b2c23..8036366807 100644 --- a/node/src/validator/mod.rs +++ b/node/src/validator/mod.rs @@ -18,6 +18,8 @@ mod router; use crate::traits::NodeInterface; use snarkos_account::Account; +#[cfg(feature = "test_network")] +use snarkos_node_bft::ledger_service::{persist_dev_committee_start_round_if_unwritten, prepare_dev_committee_options}; use snarkos_node_bft::{ledger_service::CoreLedgerService, spawn_blocking}; use snarkos_node_cdn::CdnBlockSync; use snarkos_node_consensus::Consensus; @@ -36,7 +38,7 @@ use snarkos_node_tcp::{ P2P, protocols::{Disconnect, Handshake, OnConnect, Reading}, }; -use snarkos_utilities::{NodeDataDir, SignalHandler}; +use snarkos_utilities::{DevHotswapConfig, NodeDataDir, SignalHandler}; use snarkvm::prelude::{ Ledger, @@ -48,6 +50,7 @@ use snarkvm::prelude::{ use aleo_std::StorageMode; use anyhow::{Context, Result}; +use cfg_if::cfg_if; use core::future::Future; #[cfg(feature = "locktick")] use locktick::parking_lot::Mutex; @@ -93,16 +96,28 @@ impl> Validator { dev_txs: bool, dev: Option, _slipstream_configs: &[std::path::PathBuf], - #[cfg(feature = "test_network")] dev_num_validators_for_committee_hotswap: Option, - #[cfg(not(feature = "test_network"))] _dev_num_validators_for_committee_hotswap: Option, + #[cfg(feature = "test_network")] dev_hotswap_config: Option, + #[cfg(not(feature = "test_network"))] _dev_hotswap_config: Option, signal_handler: Arc, ) -> Result { - // Initialize the ledger. + // Initialize the ledger, installing the dev committee override (when configured) + // so that snarkVM's block-sync path honors the hotswap. let ledger = { let storage_mode = storage_mode.clone(); let genesis = genesis.clone(); - spawn_blocking!(Ledger::::load(genesis, storage_mode)) + cfg_if! { + if #[cfg(feature = "test_network")] { + if let Some(config) = dev_hotswap_config + .map(|cfg| prepare_dev_committee_options(&node_data_dir, cfg)) { + spawn_blocking!(Ledger::::load_with_dev_committee(genesis, storage_mode, config?)) + } else { + spawn_blocking!(Ledger::::load(genesis, storage_mode)) + } + } else { + spawn_blocking!(Ledger::::load(genesis, storage_mode)) + } + } } .with_context(|| "Failed to initialize the ledger")?; @@ -117,21 +132,15 @@ impl> Validator { tracing::info!(target: "slipstream", "Slipstream plugin manager registered ({num_plugins} plugin(s))"); } + // If snarkVM picked the start round itself (no CLI flag and no persisted file), + // record it now so subsequent restarts are stable. + #[cfg(feature = "test_network")] + if let Some(committee) = ledger.dev_committee() { + persist_dev_committee_start_round_if_unwritten(&node_data_dir, committee.starting_round())?; + } + // Initialize the ledger service. - #[cfg(not(feature = "test_network"))] let ledger_service = Arc::new(CoreLedgerService::new(ledger.clone(), signal_handler.clone())); - #[cfg(feature = "test_network")] - // Initialize the ledger service with a deterministic dev committee. - let ledger_service = if let Some(dev_num_validators) = dev_num_validators_for_committee_hotswap { - Arc::new(CoreLedgerService::new_dev( - ledger.clone(), - signal_handler.clone(), - Some((node_data_dir.clone(), dev_num_validators)), - )) - // Initialize the ledger service without a deterministic dev committee. - } else { - Arc::new(CoreLedgerService::new_dev(ledger.clone(), signal_handler.clone(), None)) - }; // Initialize the node router. let router = Router::new( @@ -209,6 +218,9 @@ impl> Validator { } } + // Start the BFT and consensus handlers now that CDN sync is complete. This ensures that + // committed subdags are only processed after the initial sync from the CDN has finished. + node.start_consensus_handlers().await?; // Initialize the routing. node.initialize_routing().await; // Initialize the notification message loop. @@ -233,6 +245,11 @@ impl> Validator { &self.router } + /// Starts the BFT and consensus handlers. + async fn start_consensus_handlers(&self) -> Result<()> { + self.consensus.start_consensus_handlers().await + } + // /// Initialize the transaction pool. // fn initialize_transaction_pool(&self, dev: Option) -> Result<()> { // use snarkvm::{ diff --git a/node/src/validator/router.rs b/node/src/validator/router.rs index df16d27ed6..5e980ca392 100644 --- a/node/src/validator/router.rs +++ b/node/src/validator/router.rs @@ -26,7 +26,7 @@ use snarkos_node_router::messages::{ Pong, UnconfirmedTransaction, }; -use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp}; +use snarkos_node_tcp::{ConnectError, Connection, ConnectionSide, Tcp, connections::DisconnectOrigin}; use snarkvm::{ console::network::{ConsensusVersion, Network}, ledger::{block::Transaction, narwhal::Data}, @@ -81,7 +81,9 @@ where #[async_trait] impl> Disconnect for Validator { /// Any extra operations to be performed during a disconnect. - async fn handle_disconnect(&self, peer_addr: SocketAddr) { + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin) { + debug!("Physically disconnecting from {peer_addr}; origin: {origin:?}"); + if let Some(peer_ip) = self.router.resolve_to_listener(peer_addr) { self.router.downgrade_peer_to_candidate(peer_ip); diff --git a/node/tcp/src/helpers/connections.rs b/node/tcp/src/helpers/connections.rs index 60cebe1157..cca755564a 100644 --- a/node/tcp/src/helpers/connections.rs +++ b/node/tcp/src/helpers/connections.rs @@ -30,7 +30,10 @@ use tokio::{ use tracing::*; #[cfg(doc)] -use crate::protocols::{Handshake, Reading, Writing}; +use crate::{ + Tcp, + protocols::{Disconnect, Handshake, OnConnect, Reading, Writing}, +}; /// A map of all currently connected addresses to their associated connection. #[derive(Default)] @@ -171,3 +174,38 @@ pub(crate) fn create_connection_span(addr: SocketAddr, parent: &Span) -> Span { try_span!(Level::WARN); error_span!(parent: parent, "conn", addr = %addr) } + +/// Describes what triggered a disconnect, as delivered to [`Disconnect::handle_disconnect`]. +/// +/// note: Handshake failures do not appear here. A failed handshake prevents the connection +/// from ever being registered, so there is no connection to disconnect. +/// +/// note: When several events would race to trigger a disconnect on the same connection, +/// only the first to claim it is delivered to [`Disconnect::handle_disconnect`]; subsequent +/// claims are silently dropped. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum DisconnectOrigin { + /// The [`OnConnect`] task terminated abnormally before defusing its connection cleanup. + /// In practice this almost always means the user's [`OnConnect::on_connect`] implementation + /// panicked, and the disconnect is a side effect of that panic unwinding past the cleanup + /// guard. + OnConnectAbort, + /// The reader task for this connection terminated. Typical causes are the peer closing + /// its end of the socket, a decode error from the user-supplied [`Reading::Codec`], or + /// no message arriving within [`Reading::IDLE_TIMEOUT_MS`]. Often (but not always) + /// indicates a peer-side issue. + Reading, + /// The disconnect was initiated by [`Tcp::shut_down`], which tears down every active + /// connection as part of stopping the node. Unlike [`DisconnectOrigin::User`], this + /// signals that the entire node is going away - reconnection is not meaningful. + Shutdown, + /// The disconnect was explicitly requested via [`Tcp::disconnect`]. This is the only + /// origin produced directly by user code; the others all reflect events the library + /// detected internally. + User, + /// The writer task for this connection terminated. Typical causes are a [`Writing::TIMEOUT_MS`] + /// timeout while flushing, an underlying socket write error, or the message channel being + /// closed. Often correlates with the peer disappearing, but can also reflect local-side + /// pipeline problems (slow consumer, broken pipe). + Writing, +} diff --git a/node/tcp/src/protocols/disconnect.rs b/node/tcp/src/protocols/disconnect.rs index d7e899b659..4ea43b518c 100644 --- a/node/tcp/src/protocols/disconnect.rs +++ b/node/tcp/src/protocols/disconnect.rs @@ -24,7 +24,11 @@ use tracing::*; #[cfg(doc)] use crate::{Connection, protocols::Writing}; -use crate::{P2P, connections::create_connection_span, protocols::ProtocolHandler}; +use crate::{ + P2P, + connections::{DisconnectOrigin, create_connection_span}, + protocols::ProtocolHandler, +}; /// Can be used to automatically perform some extra actions when the node disconnects from its /// peer, which is especially practical if the disconnect is triggered automatically, e.g. due @@ -44,7 +48,7 @@ where /// node disconnecting from a peer. async fn enable_disconnect(&self) { let (from_node_sender, mut from_node_receiver) = mpsc::channel::<( - SocketAddr, + (SocketAddr, DisconnectOrigin), oneshot::Sender<(JoinHandle<()>, oneshot::Receiver<()>)>, )>(self.tcp().config().max_connections as usize); @@ -57,13 +61,13 @@ where trace!(parent: self_clone.tcp().span(), "spawned the Disconnect handler task"); tx.send(()).unwrap(); // safe; the channel was just opened - while let Some((peer_addr, notifier)) = from_node_receiver.recv().await { + while let Some(((peer_addr, origin), notifier)) = from_node_receiver.recv().await { let self_clone2 = self_clone.clone(); // create a channel for waiting on completion let (done_tx, done_rx) = oneshot::channel(); let handle = tokio::spawn(async move { // perform the specified extra actions - if timeout(Self::TIMEOUT, self_clone2.handle_disconnect(peer_addr)).await.is_err() { + if timeout(Self::TIMEOUT, self_clone2.handle_disconnect(peer_addr, origin)).await.is_err() { let conn_span = create_connection_span(peer_addr, self_clone2.tcp().span()); warn!(parent: conn_span, "Disconnect logic timed out"); } @@ -90,5 +94,5 @@ where /// Any extra actions to be executed during a disconnect; in order to still be able to /// communicate with the peer in the usual manner (i.e. via [`Writing`]), only its [`SocketAddr`] /// (as opposed to the related [`Connection`] object) is provided as an argument. - async fn handle_disconnect(&self, peer_addr: SocketAddr); + async fn handle_disconnect(&self, peer_addr: SocketAddr, origin: DisconnectOrigin); } diff --git a/node/tcp/src/protocols/mod.rs b/node/tcp/src/protocols/mod.rs index fe57b2b0b8..4acd70bd5c 100644 --- a/node/tcp/src/protocols/mod.rs +++ b/node/tcp/src/protocols/mod.rs @@ -17,7 +17,7 @@ //! node's lifetime and handles a specific functionality. The communication with these tasks is done via dedicated //! handler objects. -use std::{io, net::SocketAddr}; +use std::{io, net::SocketAddr, sync::atomic::Ordering}; use once_cell::race::OnceBox; use tokio::{ @@ -25,7 +25,10 @@ use tokio::{ task::JoinHandle, }; -use crate::connections::Connection; +use crate::{ + Tcp, + connections::{Connection, DisconnectOrigin}, +}; mod disconnect; mod handshake; @@ -49,7 +52,7 @@ pub(crate) struct Protocols { pub(crate) reading: OnceBox>>, pub(crate) writing: OnceBox, pub(crate) on_connect: OnceBox>>, - pub(crate) disconnect: OnceBox>, + pub(crate) disconnect: OnceBox>, } /// An object sent to a protocol handler task; the task assumes control of a protocol-relevant item `T`, @@ -71,3 +74,30 @@ impl Protocol for ProtocolHandler { let _ = self.0.send(item).await; } } + +/// This object is used to ensure that the related peer is going to be disconnected from +/// even if the owning task panics due to a user implementation error. +pub(crate) struct DisconnectOnDrop { + pub(crate) node: Option, + pub(crate) addr: SocketAddr, + pub(crate) origin: DisconnectOrigin, +} + +impl DisconnectOnDrop { + pub(crate) fn new(node: Tcp, addr: SocketAddr, origin: DisconnectOrigin) -> Self { + Self { node: Some(node), addr, origin } + } +} + +impl Drop for DisconnectOnDrop { + fn drop(&mut self) { + if let Some(node) = self.node.take() { + let (addr, origin) = (self.addr, self.origin); + let needs_recovery = + node.connections.0.read().get(&addr).is_some_and(|c| !c.disconnecting.load(Ordering::Acquire)); + if needs_recovery { + tokio::spawn(async move { node.disconnect_w_origin(addr, origin).await }); + } + } + } +} diff --git a/node/tcp/src/protocols/on_connect.rs b/node/tcp/src/protocols/on_connect.rs index 2d8373fb3e..64e69c613b 100644 --- a/node/tcp/src/protocols/on_connect.rs +++ b/node/tcp/src/protocols/on_connect.rs @@ -23,7 +23,11 @@ use crate::{ Connection, protocols::{Reading, Writing}, }; -use crate::{P2P, protocols::ProtocolHandler}; +use crate::{ + P2P, + connections::DisconnectOrigin, + protocols::{DisconnectOnDrop, ProtocolHandler}, +}; /// Can be used to automatically perform some initial actions once the connection with a peer is /// fully established. @@ -56,8 +60,13 @@ where while let Some((addr, notifier)) = from_node_receiver.recv().await { let self_clone2 = self_clone.clone(); let handle = tokio::spawn(async move { + // disconnect automatically if the OnConnect impl panics + let mut conn_cleanup = + DisconnectOnDrop::new(self_clone2.tcp().clone(), addr, DisconnectOrigin::OnConnectAbort); // perform the specified initial actions self_clone2.on_connect(addr).await; + // if there was no panic, do not disconnect - this "defuses" the auto-cleanup + conn_cleanup.node.take(); }); // notify the node that the initial actions have concluded let _ = notifier.send(handle); // can't really fail diff --git a/node/tcp/src/protocols/reading.rs b/node/tcp/src/protocols/reading.rs index 5c7e16de67..f8255ea944 100644 --- a/node/tcp/src/protocols/reading.rs +++ b/node/tcp/src/protocols/reading.rs @@ -20,7 +20,8 @@ use crate::{ ConnectionSide, P2P, Tcp, - protocols::{ProtocolHandler, ReturnableConnection}, + connections::DisconnectOrigin, + protocols::{DisconnectOnDrop, ProtocolHandler, ReturnableConnection}, }; use async_trait::async_trait; @@ -154,6 +155,9 @@ impl ReadingInternal for R { trace!(parent: &conn_span, "spawned a task for processing messages"); tx_processing.send(()).unwrap(); // safe; the channel was just opened + // disconnect automatically regardless of how this task concludes + let _conn_cleanup = DisconnectOnDrop::new(node.clone(), addr, DisconnectOrigin::Reading); + while let Some((msg, _guard)) = inbound_message_receiver.recv().await { if let Err(e) = self_clone.process_message(addr, msg).await { error!(parent: &conn_span, "can't process a message: {e}"); @@ -179,6 +183,9 @@ impl ReadingInternal for R { // this task gets aborted, so there is no need for a dedicated timeout let _ = rx_conn_ready.await; + // disconnect automatically regardless of how this task concludes + let _conn_cleanup = DisconnectOnDrop::new(node.clone(), addr, DisconnectOrigin::Reading); + // dropped message log suppression helpers let mut dropped_count: usize = 0; let mut last_drop_log = Instant::now(); @@ -227,8 +234,6 @@ impl ReadingInternal for R { None => break, // end of stream } } - - let _ = node.disconnect(addr).await; })); let _ = rx_reader.await; conn.tasks.push(reader_task); @@ -264,7 +269,10 @@ impl Decoder for CountingCodec { let initial_buf_len = src.len(); let ret = self.codec.decode(src)?; let final_buf_len = src.len(); - let read_len = initial_buf_len - final_buf_len + self.acc; + // defensive: the Decoder trait does not strictly forbid an inner codec from + // growing `src`; use saturating_sub to guard against such a possibility + let consumed = initial_buf_len.saturating_sub(final_buf_len); + let read_len = consumed + self.acc; if read_len != 0 { trace!(parent: &self.span, "read {read_len}B"); diff --git a/node/tcp/src/protocols/writing.rs b/node/tcp/src/protocols/writing.rs index b5080cb7af..42fbcb69cb 100644 --- a/node/tcp/src/protocols/writing.rs +++ b/node/tcp/src/protocols/writing.rs @@ -35,8 +35,8 @@ use crate::{ Connection, ConnectionSide, P2P, - connections::create_connection_span, - protocols::{Protocol, ProtocolHandler, ReturnableConnection}, + connections::{DisconnectOrigin, create_connection_span}, + protocols::{DisconnectOnDrop, Protocol, ProtocolHandler, ReturnableConnection}, }; type WritingSenders = Arc>>>; @@ -215,7 +215,7 @@ impl WritingInternal for W { conn_senders.write().insert(addr, outbound_message_sender); // this will automatically drop the sender upon a disconnect - let auto_cleanup = SenderCleanup { addr, senders: Arc::clone(conn_senders) }; + let sender_cleanup = SenderCleanup { addr, senders: Arc::clone(conn_senders) }; // use a channel to know when the writer task is ready let (tx_writer, rx_writer) = oneshot::channel(); @@ -229,7 +229,10 @@ impl WritingInternal for W { tx_writer.send(()).unwrap(); // safe; the channel was just opened // move the cleanup into the task that gets aborted on disconnect - let _auto_cleanup = auto_cleanup; + let _sender_cleanup = sender_cleanup; + + // disconnect automatically regardless of how this task concludes + let _conn_cleanup = DisconnectOnDrop::new(node.clone(), addr, DisconnectOrigin::Writing); while let Some(wrapped_msg) = outbound_message_receiver.recv().await { let msg = wrapped_msg.msg.downcast().unwrap(); @@ -252,8 +255,6 @@ impl WritingInternal for W { } } } - - node.disconnect(addr).await; })); let _ = rx_writer.await; conn.tasks.push(writer_task); diff --git a/node/tcp/src/tcp.rs b/node/tcp/src/tcp.rs index 538599fbbe..6761bec864 100644 --- a/node/tcp/src/tcp.rs +++ b/node/tcp/src/tcp.rs @@ -35,7 +35,7 @@ use parking_lot::Mutex; use tokio::{ io::split, net::{TcpListener, TcpSocket, TcpStream}, - sync::oneshot, + sync::{OwnedSemaphorePermit, Semaphore, oneshot}, task::{JoinHandle, JoinSet}, time::timeout, }; @@ -46,7 +46,7 @@ use crate::{ Config, KnownPeers, Stats, - connections::{Connection, ConnectionSide, Connections, create_connection_span}, + connections::{Connection, ConnectionSide, Connections, DisconnectOrigin, create_connection_span}, protocols::{Protocol, Protocols}, }; @@ -144,7 +144,7 @@ pub struct InnerTcp { /// A set of connections that have not been finalized yet. connecting: Mutex>, /// Contains objects related to the node's active connections. - connections: Connections, + pub(crate) connections: Connections, /// Collects statistics related to the node's peers. known_peers: KnownPeers, /// Contains the set of currently banned peers. @@ -280,7 +280,7 @@ impl Tcp { for addr in self.connected_addrs() { let node = self.clone(); disconnect_tasks.spawn(async move { - node.disconnect(addr).await; + node.disconnect_w_origin(addr, DisconnectOrigin::Shutdown).await; }); } while disconnect_tasks.join_next().await.is_some() {} @@ -363,9 +363,13 @@ impl Tcp { /// /// Returns true if the we were connected to the given address. pub async fn disconnect(&self, addr: SocketAddr) -> bool { + self.disconnect_w_origin(addr, DisconnectOrigin::User).await + } + + pub(crate) async fn disconnect_w_origin(&self, addr: SocketAddr, origin: DisconnectOrigin) -> bool { // claim the disconnect to avoid duplicate executions, or return early if already claimed if let Some(conn) = self.connections.0.read().get(&addr) { - if conn.disconnecting.swap(true, Relaxed) { + if conn.disconnecting.swap(true, AcqRel) { // valid connection, but someone else is already disconnecting it return false; } @@ -376,7 +380,7 @@ impl Tcp { if let Some(handler) = self.protocols.disconnect.get() { let (sender, receiver) = oneshot::channel(); - handler.trigger((addr, sender)).await; + handler.trigger(((addr, origin), sender)).await; if let Ok((handle, waiter)) = receiver.await { // register the associated task with the connection, in case // it gets terminated before its completion @@ -426,20 +430,47 @@ impl Tcp { // Use a channel to know when the listening task is ready. let (tx, rx) = oneshot::channel(); + // Cap the number of in-flight inbound connection handlers; the hard + // connection limits are still enforced inside `can_add_connection`; + // this bound exists separately to prevent per-SYN task-creation overhead + // from being unbounded under flood. + let inbound_permits = Arc::new(Semaphore::new(self.config.max_connections as usize)); + let tcp = self.clone(); let listening_task = tokio::spawn(async move { trace!(parent: tcp.span(), "Spawned the listening task"); tx.send(()).unwrap(); // safe; the channel was just opened loop { - // Await for a new connection. + // Wait for capacity before accepting. + let permit = match inbound_permits.clone().acquire_owned().await { + Ok(p) => p, + Err(_) => { + // semaphore is never closed in practice; bail defensively + error!(parent: tcp.span(), "Inbound permit semaphore closed unexpectedly"); + return; + } + }; + + // Await connection requests from peers. match listener.accept().await { - Ok((stream, addr)) => tcp.handle_connection(stream, addr), + Ok((stream, addr)) => tcp.handle_connection(stream, addr, permit), Err(e) => { - error!(parent: tcp.span(), "Failed to accept a connection: {e}"); - // if we ran out of FDs, sleep to avoid spinning 100% CPU - // while waiting for a slot to free up - tokio::time::sleep(Duration::from_millis(500)).await; + // Free the permit immediately. + drop(permit); + + match e.kind() { + // A peer aborted/reset before accept completed; no backoff - the listener is healthy. + io::ErrorKind::ConnectionAborted | io::ErrorKind::ConnectionReset => { + debug!(parent: tcp.span(), "Transient accept error: {e}"); + } + // Otherwise, assume fd / memory exhaustion (EMFILE, ENFILE, ENOBUFS, ...) + // and back off so we don't spin at 100% CPU waiting for a slot to free. + _ => { + error!(parent: tcp.span(), "Couldn't accept a connection: {e}"); + tokio::time::sleep(Duration::from_millis(500)).await; + } + } } } } @@ -485,7 +516,7 @@ impl Tcp { } /// Handles a new inbound connection. - fn handle_connection(&self, stream: TcpStream, addr: SocketAddr) { + fn handle_connection(&self, stream: TcpStream, addr: SocketAddr, permit: OwnedSemaphorePermit) { debug!(parent: self.span(), "Received a connection from {addr}"); if !self.can_add_connection() || self.is_self_connect(addr) { @@ -497,6 +528,9 @@ impl Tcp { let tcp = self.clone(); tokio::spawn(async move { + // The permit is released when the connection is accepted or fails. + let _permit = permit; + if let Err(e) = tcp.adapt_stream(stream, addr, ConnectionSide::Responder).await { tcp.connecting.lock().remove(&addr); tcp.known_peers().register_failure(addr.ip()); @@ -818,7 +852,9 @@ mod tests { // Handle the connection. let stream = TcpStream::connect(peer2_ip).await.unwrap(); - tcp.handle_connection(stream, peer2_ip); + let inbound_permits = Arc::new(Semaphore::new(1)); + let permit = inbound_permits.clone().acquire_owned().await.unwrap(); + tcp.handle_connection(stream, peer2_ip, permit); assert!(!tcp.can_add_connection()); assert_eq!(tcp.num_connected(), 1); assert_eq!(tcp.num_connecting(), 0); diff --git a/scripts/chaotic-network-runner.sh b/scripts/chaotic-network-runner.sh index 4cf3f20024..3618955ccd 100755 --- a/scripts/chaotic-network-runner.sh +++ b/scripts/chaotic-network-runner.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # ========================================== # CONFIGURATION diff --git a/scripts/delay-network.sh b/scripts/delay-network.sh index 794cc6f87e..fecf3936fc 100755 --- a/scripts/delay-network.sh +++ b/scripts/delay-network.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Set strict mode and IFS to catch unset vars, pipeline failures and whitespace issues. set -euo pipefail diff --git a/scripts/devnet.sh b/scripts/devnet.sh index 6ca1409ac5..3c6bb81207 100755 --- a/scripts/devnet.sh +++ b/scripts/devnet.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ -n "$TMUX" ]]; then echo "Detected nested tmux session. Try again after unsetting \$TMUX, e.g., using \`unset TMUX\` in bash." @@ -6,23 +6,23 @@ if [[ -n "$TMUX" ]]; then fi # Read the total number of validators from the user or use a default value of 4 -read -p "Enter the total number of validators (default: 4): " total_validators +read -r -p "Enter the total number of validators (default: 4): " total_validators total_validators=${total_validators:-4} # Read the total number of clients from the user or use a default value of 2 -read -p "Enter the total number of clients (default: 2): " total_clients +read -r -p "Enter the total number of clients (default: 2): " total_clients total_clients=${total_clients:-2} # Read the network ID from user or use a default value of 1 -read -p "Enter the network ID (mainnet = 0, testnet = 1, canary = 2) (default: 1): " network_id +read -r -p "Enter the network ID (mainnet = 0, testnet = 1, canary = 2) (default: 1): " network_id network_id=${network_id:-1} # Ask the user if they want to run 'cargo install --locked --path .' or use a pre-installed binary -read -p "Do you want to run 'cargo install --locked --path .' to build the binary? (y/n, default: y): " build_binary +read -r -p "Do you want to run 'cargo install --locked --path .' to build the binary? (y/n, default: y): " build_binary build_binary=${build_binary:-y} # Ask the user whether to clear the existing ledger history -read -p "Do you want to clear the existing ledger history? (y/n, default: n): " clear_ledger +read -r -p "Do you want to clear the existing ledger history? (y/n, default: n): " clear_ledger clear_ledger=${clear_ledger:-n} # Log verbosity is set to 1 (DEBUG) by default. @@ -32,30 +32,16 @@ verbosity=1 binary_path="" if [[ $build_binary == "y" ]]; then - # Ask the user if they want to enable validator telemetry - read -p "Do you want to enable validator telemetry? (y/n, default: y): " enable_telemetry - enable_telemetry=${enable_telemetry:-y} - # Ask the user for additional crate features (comma-separated) - read -p "Enter crate features to enable (comma separated, default: test_network): " crate_features - crate_features=${crate_features:-test_network} + read -r -p "Enter crate features to enable (comma separated, default: test_network): " crate_features + crate_features=${crate_features:-devnet} # Build command build_cmd="cargo install --locked --path ." - # Add the telemetry feature if requested - if [[ $enable_telemetry == "y" ]]; then - build_cmd+=" --features telemetry" - fi - # Add any extra features if provided if [[ -n $crate_features ]]; then - # If telemetry was also enabled, append with a comma separator - if [[ $enable_telemetry == "y" ]]; then - build_cmd+=",${crate_features}" - else - build_cmd+=" --features ${crate_features}" - fi + build_cmd+=" --features ${crate_features}" fi # Build command @@ -63,7 +49,7 @@ if [[ $build_binary == "y" ]]; then eval "$build_cmd" || exit 1 else # Ask the user whether to use a custom relative path - read -p "Do you want to run snarkos from a relative path? (e.g. ./target/debug/, defaults to the installed binary): " binary_path + read -r -p "Do you want to run snarkos from a relative path? (e.g. ./target/debug/, defaults to the installed binary): " binary_path binary_path=${binary_path:-""} fi @@ -91,8 +77,7 @@ log_dir=".logs-$(date +"%Y%m%d%H%M%S")" mkdir -p "$log_dir" # Create a new tmux session named "devnet" -tmux new-session -d -s "devnet" -n "validator-0" -if [[ $? -ne 0 ]]; then +if ! tmux new-session -d -s "devnet" -n "validator-0"; then echo "Failed to create new TMUX session." exit 1 fi @@ -105,6 +90,8 @@ if [ -z "$index_offset" ]; then fi # Generate validator indices from 0 to (total_validators - 1) +# (mapfile would be cleaner but is unavailable on the bash 3.2 shipped with macOS) +# shellcheck disable=SC2207 validator_indices=($(seq 0 $((total_validators - 1)))) # Loop through the list of validator indices and create a new window for each @@ -117,7 +104,7 @@ for validator_index in "${validator_indices[@]}"; do if [ "$validator_index" -ne 0 ]; then # We don't need to create a window for the first validator because the tmux session already starts with one window. - tmux new-window -t "devnet:$window_index" -n $name + tmux new-window -t "devnet:$window_index" -n "$name" fi # Send the command to start the validator to the new window and capture output to the log file @@ -126,6 +113,7 @@ done if [ "$total_clients" -ne 0 ]; then # Generate client indices from 0 to (total_clients - 1) + # shellcheck disable=SC2207 client_indices=($(seq 0 $((total_clients - 1)))) # Loop through the list of client indices and create a new window for each @@ -137,7 +125,7 @@ if [ "$total_clients" -ne 0 ]; then window_index=$((client_index + total_validators + index_offset)) # Create a new window with a unique name - tmux new-window -t "devnet:$window_index" -n $name + tmux new-window -t "devnet:$window_index" -n "$name" # Send the command to start the client to the new window and capture output to the log file tmux send-keys -t "devnet:$window_index" "${binary_path}snarkos start --nodisplay --network $network_id --dev $window_index --dev-num-validators $total_validators --client --logfile $log_file --verbosity $verbosity" C-m diff --git a/scripts/lint.sh b/scripts/lint.sh new file mode 100755 index 0000000000..83f3f9ead2 --- /dev/null +++ b/scripts/lint.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# +# Runs the same lints as CI: clippy, rustfmt, and shellcheck. +# Invoked by the rusty-hook pre-commit hook (see .rusty-hook.toml). + +set -e + +echo "Running clippy..." +cargo clippy --workspace --all-targets --all-features -- -D warnings + +echo "Checking rustfmt..." +cargo +nightly fmt --all -- --check + +if command -v shellcheck >/dev/null; then + echo "Running shellcheck..." + shellcheck -x .ci/*.sh scripts/*.sh +else + echo "warning: shellcheck not installed, skipping script lint (CI will still run it)" +fi diff --git a/scripts/run-core-client.sh b/scripts/run-core-client.sh index e9c77cca63..59291e19a8 100755 --- a/scripts/run-core-client.sh +++ b/scripts/run-core-client.sh @@ -1,13 +1,13 @@ -#!/bin/bash +#!/usr/bin/env bash -# USAGE examples: - # CLI with env vars: PEERS=“validator_ip:4130,core_client_ip_1:4130,core_client_ip_2:4130,core_client_ip_3:4130,outer_client_ip_1:4130,... ./run-core-client.sh +# USAGE examples: + # CLI with env vars: PEERS="validator_ip:4130,core_client_ip_1:4130,core_client_ip_2:4130,core_client_ip_3:4130,outer_client_ip_1:4130,..." ./run-core-client.sh # CLI with prompts for vars: ./run-core-client.sh # If the env var PEERS is not set, prompt for it if [ -z "${PEERS}" ] then - read -r -p "Enter the peers (comma-separated) (e.g., “validator_ip:4130,core_client_ip_1:4130,core_client_ip_2:4130,core_client_ip_3:4130,outer_client_ip_1:4130,...): " + read -r -p "Enter the peers (comma-separated) (e.g., \"validator_ip:4130,core_client_ip_1:4130,core_client_ip_2:4130,core_client_ip_3:4130,outer_client_ip_1:4130,...\"): " PEERS=$REPLY fi @@ -17,9 +17,9 @@ then exit 1 fi -COMMAND='cargo run --release -- start --nodisplay --client --node 0.0.0.0:4130 --peers ${PEERS} --verbosity 1 --norest' +COMMAND="cargo run --release -- start --nodisplay --client --node 0.0.0.0:4130 --peers ${PEERS} --verbosity 1 --norest" -for word in $*; +for word in "$@"; do COMMAND="${COMMAND} ${word}" done diff --git a/scripts/run-outer-client.sh b/scripts/run-outer-client.sh index 92f0173d98..6f98fc002d 100755 --- a/scripts/run-outer-client.sh +++ b/scripts/run-outer-client.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # USAGE examples: # CLI with env vars: PEERS=core_client_ip_1:4130,core_client_ip_2:4130,core_client_ip_3:4130,outer_client_ip_1:4130,... ./run-outer-client.sh @@ -17,7 +17,7 @@ else COMMAND="cargo run --release -- start --nodisplay --client --node 0.0.0.0:4130 --peers ${PEERS} --verbosity 1 --rest 0.0.0.0:3030" fi -for word in $*; +for word in "$@"; do COMMAND="${COMMAND} ${word}" done diff --git a/scripts/run-prover.sh b/scripts/run-prover.sh index cbaeb65d70..dda4b03861 100755 --- a/scripts/run-prover.sh +++ b/scripts/run-prover.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # USAGE examples: # CLI with env vars: PROVER_PRIVATE_KEY=APrivateKey1... ./run-prover.sh # CLI with prompts for vars: ./run-prover.sh diff --git a/scripts/run-validator.sh b/scripts/run-validator.sh index 3cc71f0448..16ca619ae3 100644 --- a/scripts/run-validator.sh +++ b/scripts/run-validator.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # USAGE examples: # CLI with env vars: VALIDATOR_PRIVATE_KEY=APrivateKey1... PEERS=core_client_ip_1:4130,core_client_ip_2:4130,... VALIDATORS=validator_ip_1:5000,validator_ip_2:5000,... ./run-validator.sh # CLI with prompts for vars: ./run-validator.sh @@ -42,22 +42,13 @@ then exit 1 fi -# Ask the user if they want to enable validator telemetry -read -p "Do you want to enable validator telemetry? (y/n, default: y): " enable_telemetry -enable_telemetry=${enable_telemetry:-y} - # Start building the base command COMMAND="cargo run --release" -# Add telemetry feature if enabled -if [[ $enable_telemetry == "y" ]]; then - COMMAND+=" --features telemetry" -fi - # Add the arguments after the '--' COMMAND+=" -- start --nodisplay --validator --bft 0.0.0.0:5000 --node 0.0.0.0:4130 --peers ${PEERS} --validators ${VALIDATORS} --norest --private-key ${VALIDATOR_PRIVATE_KEY}" -for word in $*; +for word in "$@"; do COMMAND="${COMMAND} ${word}" done diff --git a/snarkos/main.rs b/snarkos/main.rs index 3ddca88939..5a46c10528 100644 --- a/snarkos/main.rs +++ b/snarkos/main.rs @@ -187,12 +187,13 @@ fn check_for_version() { if let Some(first_arg) = env::args().nth(1) && ["--version", "-V"].contains(&&*first_arg) { + let version = env!("SNARKOS_VERSION"); let branch = GIT_HEAD_REF.unwrap_or("unknown_branch"); let commit = GIT_COMMIT_HASH.unwrap_or("unknown_commit"); let mut features = FEATURES_LOWERCASE_STR.to_owned(); features.retain(|c| c != ' '); - print_info!("snarkos {branch} {commit} features=[{features}]"); + print_info!("snarkos {version} {branch} {commit} features=[{features}]"); exit(0); } diff --git a/utilities/src/lib.rs b/utilities/src/lib.rs index 8c64971457..c9063edc6d 100644 --- a/utilities/src/lib.rs +++ b/utilities/src/lib.rs @@ -26,3 +26,10 @@ pub use callback_handle::CallbackHandle; /// Seed used for deterministic RNG in development mode. pub const DEVELOPMENT_MODE_RNG_SEED: u64 = 1234567890u64; + +/// Configuration for the deterministic dev committee hotswap (`--dev-on-prod`). +#[derive(Clone, Copy, Debug)] +pub struct DevHotswapConfig { + /// Number of validators in the dev committee. + pub dev_num_validators: u16, +} diff --git a/version_env.rs b/version_env.rs new file mode 100644 index 0000000000..852ebc692b --- /dev/null +++ b/version_env.rs @@ -0,0 +1,48 @@ +// Copyright (c) 2019-2026 Provable Inc. +// This file is part of the snarkOS library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{ + env, + fs, + path::{Path, PathBuf}, +}; + +pub fn emit_version_env() { + let release_version = find_release_version_path().unwrap_or_else(|| { + panic!( + "Failed to locate '.cargo/release-version' starting from '{}'", + env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| "".to_string()) + ) + }); + + println!("cargo:rerun-if-changed={}", release_version.display()); + + let version = fs::read_to_string(&release_version) + .unwrap_or_else(|err| panic!("Failed to read '{}': {err}", release_version.display())); + let version = version.trim(); + let version = version.strip_prefix('v').unwrap_or(version); + assert!(!version.is_empty(), "'{}' did not contain a version", release_version.display()); + + println!("cargo:rustc-env=SNARKOS_VERSION={version}"); +} + +fn find_release_version_path() -> Option { + let manifest_dir = env::var_os("CARGO_MANIFEST_DIR")?; + + Path::new(&manifest_dir) + .ancestors() + .map(|dir| dir.join(".cargo").join("release-version")) + .find(|path| path.is_file()) +}