diff --git a/Cargo.lock b/Cargo.lock index 804f9fc..291613f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "argon2" version = "0.5.3" @@ -216,9 +222,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bytemuck" @@ -289,9 +295,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.58" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -299,9 +305,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -383,9 +389,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -555,6 +561,12 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -605,6 +617,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -665,9 +683,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -701,6 +719,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "ghash" version = "0.5.1" @@ -731,13 +762,28 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + [[package]] name = "hashlink" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -760,15 +806,15 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hidapi" -version = "2.6.4" +version = "2.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "565dd4c730b8f8b2c0fb36df6be12e5470ae10895ddcc4e9dcfbfb495de202b0" +checksum = "d1b71e1f4791fb9e93b9d7ee03d70b501ab48f6151432fbcadeabc30fe15396e" dependencies = [ "cc", "cfg-if", "libc", "pkg-config", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -979,6 +1025,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -1012,6 +1064,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + [[package]] name = "inout" version = "0.1.4" @@ -1051,9 +1115,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jiff" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c867c356cc096b33f4981825ab281ecba3db0acefe60329f044c1789d94c6543" +checksum = "b3e3d65f018c6ae946ab16e80944b97096ed73c35b221d1c478a6c81d8f57940" dependencies = [ "jiff-static", "log", @@ -1064,9 +1128,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7946b4325269738f270bb55b3c19ab5c5040525f83fd625259422a9d25d9be5" +checksum = "a17c2b211d863c7fde02cbea8a3c1a439b98e109286554f2860bdded7ff83818" dependencies = [ "proc-macro2", "quote", @@ -1075,9 +1139,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -1111,6 +1175,12 @@ dependencies = [ "spin", ] +[[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.182" @@ -1147,9 +1217,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -1207,9 +1277,9 @@ dependencies = [ [[package]] name = "ml-kem" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcaee19a45f916d98f24a551cc9a2cdae705a040e66f3cbc4f3a282ea6a2e982" +checksum = "8de49b3df74c35498c0232031bb7e85f9389f913e2796169c8ab47a53993a18f" dependencies = [ "hybrid-array", "kem", @@ -1407,9 +1477,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -1478,6 +1548,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -1700,9 +1780,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" @@ -1820,9 +1900,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags 2.11.0", "errno", @@ -1833,9 +1913,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "once_cell", "ring", @@ -1880,7 +1960,7 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "salvium-cli" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "clap", "dirs", @@ -1902,7 +1982,7 @@ dependencies = [ [[package]] name = "salvium-consensus" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "hex", "salvium-types", @@ -1914,7 +1994,7 @@ dependencies = [ [[package]] name = "salvium-crypto" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "aes-gcm", "argon2", @@ -1940,7 +2020,7 @@ dependencies = [ [[package]] name = "salvium-ffi" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "hex", "log", @@ -1958,7 +2038,7 @@ dependencies = [ [[package]] name = "salvium-miner" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "clap", "hex", @@ -1973,7 +2053,7 @@ dependencies = [ [[package]] name = "salvium-miner-gr" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "cc", "clap", @@ -1985,7 +2065,7 @@ dependencies = [ [[package]] name = "salvium-miner-v2" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "cc", "clap", @@ -2000,7 +2080,7 @@ dependencies = [ [[package]] name = "salvium-multisig" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "curve25519-dalek", "hex", @@ -2016,7 +2096,7 @@ dependencies = [ [[package]] name = "salvium-rpc" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "base64", "hex", @@ -2031,7 +2111,7 @@ dependencies = [ [[package]] name = "salvium-sync-bench" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "clap", "env_logger", @@ -2048,7 +2128,7 @@ dependencies = [ [[package]] name = "salvium-tx" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "curve25519-dalek", "getrandom 0.2.17", @@ -2066,7 +2146,7 @@ dependencies = [ [[package]] name = "salvium-types" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "hex", "serde", @@ -2076,7 +2156,7 @@ dependencies = [ [[package]] name = "salvium-wallet" -version = "1.0.7-r013" +version = "1.0.7-r014" dependencies = [ "aes-gcm", "chacha20", @@ -2297,9 +2377,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.116" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2328,12 +2408,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.24.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2533,6 +2613,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "universal-hash" version = "0.5.1" @@ -2620,10 +2706,19 @@ dependencies = [ ] [[package]] -name = "wasm-bindgen" -version = "0.2.108" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -2634,9 +2729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", "futures-util", @@ -2648,9 +2743,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2658,9 +2753,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", @@ -2671,18 +2766,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.58" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45649196a53b0b7a15101d845d44d2dda7374fc1b5b5e2bbf58b7577ff4b346d" +checksum = "6311c867385cc7d5602463b31825d454d0837a3aba7cdb5e56d5201792a3f7fe" dependencies = [ "async-trait", "cast", @@ -2702,9 +2797,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.58" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f579cdd0123ac74b94e1a4a72bd963cf30ebac343f2df347da0b8df24cdebed2" +checksum = "67008cdde4769831958536b0f11b3bdd0380bde882be17fff9c2f34bb4549abd" dependencies = [ "proc-macro2", "quote", @@ -2713,15 +2808,49 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-shared" -version = "0.2.108" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8145dd1593bf0fb137dbfa85b8be79ec560a447298955877804640e40c2d6ea" +checksum = "cfe29135b180b72b04c74aa97b2b4a2ef275161eff9a6c7955ea9eaedc7e1d4e" + +[[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", + "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.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -2997,6 +3126,88 @@ 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-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", + "prettyplease", + "syn", + "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", + "syn", + "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.0", + "indexmap", + "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", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -3029,18 +3240,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 2d05c06..c32daff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ members = [ ] [workspace.package] -version = "1.0.7-r013" +version = "1.0.7-r014" edition = "2021" license = "LicenseRef-Salvium-RS" repository = "https://github.com/salvium/salvium-rs" diff --git a/crates/salvium-cli/src/commands/multisig.rs b/crates/salvium-cli/src/commands/multisig.rs index f519d19..75f6e4e 100644 --- a/crates/salvium-cli/src/commands/multisig.rs +++ b/crates/salvium-cli/src/commands/multisig.rs @@ -264,7 +264,8 @@ pub async fn transfer_multisig(ctx: &AppContext, address: &str, amount_str: &str println!(" Amount: {} SAL", format_sal_u64(amount)); println!(); - let fee_priority = salvium_tx::fee::FeePriority::Normal; + let fee_priority = + tx_common::adjust_priority(salvium_tx::fee::FeePriority::Default, &ctx.pool).await; let est_fee = salvium_tx::estimate_tx_fee(2, 2, 16, true, 0x04, fee_priority); println!(" Estimated fee: {} SAL", format_sal_u64(est_fee)); diff --git a/crates/salvium-cli/src/commands/transfers.rs b/crates/salvium-cli/src/commands/transfers.rs index 4fb9737..4b4b38f 100644 --- a/crates/salvium-cli/src/commands/transfers.rs +++ b/crates/salvium-cli/src/commands/transfers.rs @@ -16,6 +16,7 @@ pub async fn transfer(ctx: &AppContext, address: &str, amount_str: &str, priorit let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; println!("Transfer:"); println!(" To: {}", address); @@ -91,7 +92,8 @@ pub async fn stake(ctx: &AppContext, amount_str: &str) -> Result { println!(" Amount: {} SAL", format_sal_u64(amount)); println!(); - let fee_priority = salvium_tx::fee::FeePriority::Normal; + let fee_priority = + tx_common::adjust_priority(salvium_tx::fee::FeePriority::Default, &ctx.pool).await; let est_fee = salvium_tx::estimate_tx_fee(2, 2, 16, true, 0x04, fee_priority); println!(" Estimated fee: {} SAL", format_sal_u64(est_fee)); println!(); @@ -155,6 +157,7 @@ pub async fn burn(ctx: &AppContext, amount_str: &str, priority: &str) -> Result let amount = parse_sal_amount(amount_str)?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; println!("Burn:"); println!(" Amount: {} SAL", format_sal_u64(amount)); @@ -221,6 +224,7 @@ pub async fn convert( let amount = parse_sal_amount(amount_str)?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; println!("Convert:"); println!(" Amount: {} {}", format_sal_u64(amount), source_asset); @@ -290,6 +294,7 @@ pub async fn audit(ctx: &AppContext, priority: &str) -> Result { } let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; // Audit sweeps all funds back to self as a verifiable on-chain proof. let balance = wallet.get_balance("SAL", 0)?; @@ -360,6 +365,7 @@ pub async fn locked_transfer( let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; println!("Locked Transfer:"); println!(" To: {}", address); @@ -421,6 +427,7 @@ pub async fn sweep_all(ctx: &AppContext, address: &str, priority: &str) -> Resul let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; let balance = wallet.get_balance("SAL", 0)?; let unlocked: u64 = balance.unlocked_balance.parse().unwrap_or(0); @@ -492,6 +499,7 @@ pub async fn sweep_below( let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; // Get outputs below threshold. let query = salvium_crypto::storage::OutputQuery { @@ -580,6 +588,7 @@ pub async fn sweep_single( let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; let output = wallet .get_output(key_image)? @@ -669,7 +678,8 @@ pub async fn sweep_unmixable(ctx: &AppContext) -> Result { return Ok(()); } - let fee_priority = salvium_tx::fee::FeePriority::Normal; + let fee_priority = + tx_common::adjust_priority(salvium_tx::fee::FeePriority::Default, &ctx.pool).await; let pipeline = TxPipeline::new(&wallet, ctx, fee_priority); let est_fee = salvium_tx::estimate_tx_fee(unmixable.len(), 1, 16, true, 0x04, fee_priority); @@ -724,6 +734,7 @@ pub async fn locked_sweep_all( let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; let balance = wallet.get_balance("SAL", 0)?; let unlocked: u64 = balance.unlocked_balance.parse().unwrap_or(0); @@ -784,6 +795,7 @@ pub async fn return_payment(ctx: &AppContext, tx_hash: &str, priority: &str) -> } let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; // Look up the incoming TX to find the sender's info. let query = salvium_crypto::storage::TxQuery { @@ -888,6 +900,7 @@ pub async fn sweep_account( let parsed_addr = salvium_types::address::parse_address(address) .map_err(|e| format!("invalid destination address: {}", e))?; let fee_priority = tx_common::parse_fee_priority(priority); + let fee_priority = tx_common::adjust_priority(fee_priority, &ctx.pool).await; // Get outputs for the specific account (and optional subaddress filter). let query = salvium_crypto::storage::OutputQuery { diff --git a/crates/salvium-cli/src/main.rs b/crates/salvium-cli/src/main.rs index 61f569c..abf0d54 100644 --- a/crates/salvium-cli/src/main.rs +++ b/crates/salvium-cli/src/main.rs @@ -830,6 +830,7 @@ pub struct AppContext { pub daemon_url: String, pub extra_nodes: Vec, pub wallet_path: PathBuf, + pub pool: salvium_rpc::NodePool, } impl AppContext { @@ -843,7 +844,13 @@ impl AppContext { default_wallet_dir(&cli.network).join("wallet.db") }; - Self { network, daemon_url, extra_nodes: cli.nodes.clone(), wallet_path } + let pool = salvium_rpc::NodePool::new(salvium_rpc::PoolConfig { + network, + primary_url: Some(daemon_url.clone()), + ..Default::default() + }); + + Self { network, daemon_url, extra_nodes: cli.nodes.clone(), wallet_path, pool } } } diff --git a/crates/salvium-cli/src/tx_common.rs b/crates/salvium-cli/src/tx_common.rs index 6a2d964..71be26c 100644 --- a/crates/salvium-cli/src/tx_common.rs +++ b/crates/salvium-cli/src/tx_common.rs @@ -4,7 +4,7 @@ //! → sign → submit logic used by transfer, stake, burn, convert, sweep, etc. use crate::AppContext; -use salvium_rpc::DaemonRpc; +use salvium_rpc::NodePool; use salvium_wallet::Wallet; type Result = std::result::Result>; @@ -20,7 +20,7 @@ pub struct SignedResult { /// Shared pipeline for building, signing, and optionally submitting transactions. pub struct TxPipeline<'a> { pub wallet: &'a Wallet, - pub daemon: DaemonRpc, + pub pool: NodePool, pub fee_priority: salvium_tx::fee::FeePriority, } @@ -30,7 +30,7 @@ impl<'a> TxPipeline<'a> { ctx: &AppContext, fee_priority: salvium_tx::fee::FeePriority, ) -> Self { - Self { wallet, daemon: DaemonRpc::new(&ctx.daemon_url), fee_priority } + Self { wallet, pool: ctx.pool.clone(), fee_priority } } /// Select UTXOs for the given amount + fee, derive spend keys, and return @@ -135,8 +135,8 @@ impl<'a> TxPipeline<'a> { inputs: &[InputData], ) -> Result> { println!("Fetching decoy data from daemon..."); - let info = self.daemon.get_info().await?; - let dist = self.daemon.get_output_distribution(&[0], 0, info.height, true, "").await?; + let info = self.pool.get_info().await?; + let dist = self.pool.get_output_distribution(&[0], 0, info.height, true, "").await?; let rct_offsets = dist.first().ok_or("no output distribution returned from daemon")?.distribution.clone(); let decoy_selector = salvium_tx::DecoySelector::new(rct_offsets) @@ -154,7 +154,7 @@ impl<'a> TxPipeline<'a> { .iter() .map(|&idx| salvium_rpc::daemon::OutputRequest { amount: 0, index: idx }) .collect(); - let outs_info = self.daemon.get_outs(&requests, false, "").await?; + let outs_info = self.pool.get_outs(&requests, false, "").await?; let mut ring_keys = Vec::with_capacity(ring_size); let mut ring_commitments = Vec::with_capacity(ring_size); @@ -199,8 +199,8 @@ impl<'a> TxPipeline<'a> { println!("Submitting transaction..."); let result = self - .daemon - .send_raw_transaction(&tx_hex, false) + .pool + .send_raw_transaction_ex(&tx_hex, false, true, "SAL") .await .map_err(|e| format!("submission: {}", e))?; @@ -245,9 +245,79 @@ pub fn hex_to_32(s: &str) -> std::result::Result<[u8; 32], Box salvium_tx::fee::FeePriority { match s { "low" => salvium_tx::fee::FeePriority::Low, + "normal" => salvium_tx::fee::FeePriority::Normal, "high" => salvium_tx::fee::FeePriority::High, "urgent" | "highest" => salvium_tx::fee::FeePriority::Highest, - _ => salvium_tx::fee::FeePriority::Normal, + _ => salvium_tx::fee::FeePriority::Default, + } +} + +/// Adjust fee priority based on network conditions (matches wallet2::adjust_priority). +/// +/// When priority is `Default` (user didn't explicitly choose), queries the daemon: +/// 1. If mempool has pending transactions -> Normal (5x) +/// 2. If recent blocks are >80% full -> Normal (5x) +/// 3. Otherwise -> Low (1x) +/// +/// Explicit priorities (Low/Normal/High/Highest) pass through unchanged. +pub async fn adjust_priority( + priority: salvium_tx::fee::FeePriority, + pool: &NodePool, +) -> salvium_tx::fee::FeePriority { + use salvium_tx::fee::FeePriority; + + if priority != FeePriority::Default { + return priority; + } + match try_adjust_priority(pool).await { + Ok(adjusted) => adjusted, + Err(e) => { + log::debug!("adjust_priority failed, using Normal: {e}"); + FeePriority::Normal + } + } +} + +async fn try_adjust_priority( + pool: &NodePool, +) -> std::result::Result { + use salvium_tx::fee::FeePriority; + + let info = pool.get_info().await.map_err(|e| e.to_string())?; + + // 1. Mempool backlog -> Normal + if info.tx_pool_size > 0 { + log::info!("adjust_priority: mempool has {} txs, using Normal", info.tx_pool_size); + return Ok(FeePriority::Normal); + } + + // 2. Block fullness check + let block_weight_limit = info + .extra + .get("block_weight_limit") + .and_then(|v| v.as_u64()) + .ok_or("block_weight_limit not in get_info")?; + let full_reward_zone = block_weight_limit / 2; + if full_reward_zone == 0 { + return Ok(FeePriority::Normal); + } + + let height = info.height; + if height < 10 { + return Ok(FeePriority::Normal); + } + + let headers = + pool.get_block_headers_range(height - 10, height - 1).await.map_err(|e| e.to_string())?; + let weight_sum: u64 = headers.iter().map(|h| h.block_weight).sum(); + let fullness_pct = 100 * weight_sum / (10 * full_reward_zone); + + if fullness_pct > 80 { + log::info!("adjust_priority: blocks {fullness_pct}% full, using Normal"); + Ok(FeePriority::Normal) + } else { + log::info!("adjust_priority: blocks {fullness_pct}% full, using Low"); + Ok(FeePriority::Low) } } diff --git a/crates/salvium-ffi/src/daemon.rs b/crates/salvium-ffi/src/daemon.rs index ad378db..2089918 100644 --- a/crates/salvium-ffi/src/daemon.rs +++ b/crates/salvium-ffi/src/daemon.rs @@ -148,6 +148,20 @@ pub unsafe extern "C" fn salvium_daemon_force_race(handle: *mut c_void) -> i32 { }) } +/// Get per-node status as JSON. +/// +/// Returns a JSON array with each node's health, latency, and failure info. +/// Caller must free with `salvium_string_free()`. +#[no_mangle] +pub unsafe extern "C" fn salvium_daemon_node_status(handle: *mut c_void) -> *mut c_char { + ffi_try_string(|| { + let dh = unsafe { borrow_handle::(handle) }?; + let rt = crate::runtime(); + let status = rt.block_on(dh.pool.get_node_status()); + serde_json::to_string(&status).map_err(|e| e.to_string()) + }) +} + /// Close a daemon handle. /// /// If the daemon is in use by a sync operation, this blocks until the sync diff --git a/crates/salvium-ffi/src/transfer.rs b/crates/salvium-ffi/src/transfer.rs index f165fb1..42ac8ad 100644 --- a/crates/salvium-ffi/src/transfer.rs +++ b/crates/salvium-ffi/src/transfer.rs @@ -73,7 +73,7 @@ struct SweepParams { } fn default_priority() -> String { - "normal".into() + "default".into() } fn default_ring_size() -> usize { 16 @@ -82,10 +82,70 @@ fn default_ring_size() -> usize { fn parse_priority(s: &str) -> FeePriority { match s.to_lowercase().as_str() { "low" => FeePriority::Low, - "normal" | "default" => FeePriority::Normal, + "normal" => FeePriority::Normal, "high" | "elevated" => FeePriority::High, "highest" | "urgent" => FeePriority::Highest, - _ => FeePriority::Normal, + _ => FeePriority::Default, + } +} + +/// Adjust fee priority based on network conditions (matches wallet2::adjust_priority). +/// +/// When priority is `Default` (user didn't explicitly choose), queries the daemon: +/// 1. If mempool has pending transactions -> Normal (5x) +/// 2. If recent blocks are >80% full -> Normal (5x) +/// 3. Otherwise -> Low (1x) +/// +/// Explicit priorities (Low/Normal/High/Highest) pass through unchanged. +async fn adjust_priority(priority: FeePriority, pool: &salvium_rpc::NodePool) -> FeePriority { + if priority != FeePriority::Default { + return priority; + } + match try_adjust_priority(pool).await { + Ok(adjusted) => adjusted, + Err(e) => { + log::debug!("adjust_priority failed, using Normal: {e}"); + FeePriority::Normal + } + } +} + +async fn try_adjust_priority(pool: &salvium_rpc::NodePool) -> Result { + let info = pool.get_info().await.map_err(|e| e.to_string())?; + + // 1. Mempool backlog -> Normal + if info.tx_pool_size > 0 { + log::info!("adjust_priority: mempool has {} txs, using Normal", info.tx_pool_size); + return Ok(FeePriority::Normal); + } + + // 2. Block fullness check + let block_weight_limit = info + .extra + .get("block_weight_limit") + .and_then(|v| v.as_u64()) + .ok_or("block_weight_limit not in get_info")?; + let full_reward_zone = block_weight_limit / 2; + if full_reward_zone == 0 { + return Ok(FeePriority::Normal); + } + + let height = info.height; + if height < 10 { + return Ok(FeePriority::Normal); + } + + let headers = + pool.get_block_headers_range(height - 10, height - 1).await.map_err(|e| e.to_string())?; + let weight_sum: u64 = headers.iter().map(|h| h.block_weight).sum(); + let fullness_pct = 100 * weight_sum / (10 * full_reward_zone); + + if fullness_pct > 80 { + log::info!("adjust_priority: blocks {fullness_pct}% full, using Normal"); + Ok(FeePriority::Normal) + } else { + log::info!("adjust_priority: blocks {fullness_pct}% full, using Low"); + Ok(FeePriority::Low) } } @@ -130,6 +190,7 @@ pub unsafe extern "C" fn salvium_wallet_transfer( let rt = crate::runtime(); rt.block_on(async { + let priority = adjust_priority(priority, &dh.pool).await; let daemon = dh.pool.active_daemon().await; do_transfer(&wh.wallet, &daemon, ¶ms, priority).await }) @@ -173,6 +234,7 @@ pub unsafe extern "C" fn salvium_wallet_stake( let rt = crate::runtime(); rt.block_on(async { + let priority = adjust_priority(priority, &dh.pool).await; let daemon = dh.pool.active_daemon().await; do_stake(&wh.wallet, &daemon, ¶ms, priority, false).await }) @@ -209,6 +271,7 @@ pub unsafe extern "C" fn salvium_wallet_stake_dry_run( let rt = crate::runtime(); rt.block_on(async { + let priority = adjust_priority(priority, &dh.pool).await; let daemon = dh.pool.active_daemon().await; do_stake(&wh.wallet, &daemon, ¶ms, priority, true).await }) @@ -254,6 +317,7 @@ pub unsafe extern "C" fn salvium_wallet_sweep( let rt = crate::runtime(); rt.block_on(async { + let priority = adjust_priority(priority, &dh.pool).await; let daemon = dh.pool.active_daemon().await; do_sweep(&wh.wallet, &daemon, ¶ms, priority).await }) @@ -294,6 +358,7 @@ pub unsafe extern "C" fn salvium_wallet_transfer_dry_run( let rt = crate::runtime(); rt.block_on(async { + let priority = adjust_priority(priority, &dh.pool).await; let daemon = dh.pool.active_daemon().await; do_transfer(&wh.wallet, &daemon, ¶ms, priority).await }) diff --git a/crates/salvium-rpc/src/lib.rs b/crates/salvium-rpc/src/lib.rs index c85d4e1..eba03ea 100644 --- a/crates/salvium-rpc/src/lib.rs +++ b/crates/salvium-rpc/src/lib.rs @@ -27,7 +27,7 @@ pub mod wallet_rpc; pub use client::RpcClient; pub use daemon::DaemonRpc; pub use error::RpcError; -pub use pool::{DistributedBatchResult, NodePool, PoolConfig}; +pub use pool::{DistributedBatchResult, NodePool, NodeStatusInfo, PoolConfig}; pub use wallet_rpc::WalletRpc; /// Seed nodes per network. diff --git a/crates/salvium-rpc/src/pool.rs b/crates/salvium-rpc/src/pool.rs index 2d14340..745f049 100644 --- a/crates/salvium-rpc/src/pool.rs +++ b/crates/salvium-rpc/src/pool.rs @@ -18,6 +18,18 @@ use tokio::sync::RwLock; // Types // ───────────────────────────────────────────────────────────────────────────── +/// Per-node status snapshot returned by [`NodePool::get_node_status()`]. +#[derive(Debug, Clone, serde::Serialize)] +pub struct NodeStatusInfo { + pub url: String, + pub is_seed: bool, + pub is_active: bool, + pub is_healthy: bool, + pub latency_ms: Option, + pub last_probed_secs_ago: Option, + pub consecutive_failures: u32, +} + struct NodeState { daemon: DaemonRpc, url: String, @@ -180,6 +192,25 @@ impl NodePool { inner.nodes[inner.active_index].url.clone() } + /// Return a snapshot of every node's health, latency, and failure status. + pub async fn get_node_status(&self) -> Vec { + let inner = self.inner.read().await; + inner + .nodes + .iter() + .enumerate() + .map(|(idx, node)| NodeStatusInfo { + url: node.url.clone(), + is_seed: node.is_seed, + is_active: idx == inner.active_index, + is_healthy: node.is_healthy, + latency_ms: node.last_latency.map(|d| d.as_millis() as u64), + last_probed_secs_ago: node.last_probed.map(|i| i.elapsed().as_secs()), + consecutive_failures: node.consecutive_failures, + }) + .collect() + } + // ── Racing ────────────────────────────────────────────────────────── /// Check if enough time has elapsed since the last race; if so, run one. diff --git a/crates/salvium-tx/src/fee.rs b/crates/salvium-tx/src/fee.rs index 0cbc6d1..01dff8c 100644 --- a/crates/salvium-tx/src/fee.rs +++ b/crates/salvium-tx/src/fee.rs @@ -17,6 +17,9 @@ pub const DEFAULT_RING_SIZE: usize = 16; /// Fee priority levels. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FeePriority { + /// Unset — resolves to Low or Normal based on network load via `adjust_priority`. + /// Falls back to Normal (5x) if adjustment fails. + Default, Low, Normal, High, @@ -27,6 +30,7 @@ impl FeePriority { /// Priority multiplier applied to the base fee. pub fn multiplier(&self) -> u64 { match self { + FeePriority::Default => 5, // safe fallback = Normal FeePriority::Low => 1, FeePriority::Normal => 5, FeePriority::High => 25, @@ -226,6 +230,7 @@ mod tests { #[test] fn test_fee_priority_multipliers() { + assert_eq!(FeePriority::Default.multiplier(), 5); assert_eq!(FeePriority::Low.multiplier(), 1); assert_eq!(FeePriority::Normal.multiplier(), 5); assert_eq!(FeePriority::High.multiplier(), 25);