diff --git a/ows/Cargo.lock b/ows/Cargo.lock index 0c0892826..2f32511c2 100644 --- a/ows/Cargo.lock +++ b/ows/Cargo.lock @@ -108,12 +108,27 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -267,6 +282,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "bit-set" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ddef2995421ab6a5c779542c81ee77c115206f4ad9d5a8e05f4ff49716a3dd" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" + [[package]] name = "bitcoin" version = "0.32.8" @@ -343,6 +373,17 @@ dependencies = [ "digest", ] +[[package]] +name = "blake2b_simd" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -352,6 +393,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bs58" version = "0.5.1" @@ -368,6 +418,26 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -466,6 +536,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "codespan-reporting" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681" +dependencies = [ + "unicode-width", +] + [[package]] name = "coins-bip32" version = "0.11.1" @@ -541,6 +620,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -562,6 +647,37 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -698,6 +814,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -709,6 +835,15 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dyn-clone" version = "1.0.20" @@ -869,6 +1004,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -984,6 +1125,40 @@ dependencies = [ "polyval", ] +[[package]] +name = "gpu-allocator" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" +dependencies = [ + "ash", + "hashbrown 0.16.1", + "log", + "presser", + "thiserror 2.0.18", + "windows", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags", +] + [[package]] name = "group" version = "0.13.0" @@ -1014,6 +1189,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + [[package]] name = "hash32" version = "0.3.1" @@ -1037,7 +1224,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -1046,6 +1233,11 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "heapless" @@ -1084,6 +1276,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + [[package]] name = "hkdf" version = "0.12.4" @@ -1483,6 +1681,16 @@ version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + [[package]] name = "libm" version = "0.2.16" @@ -1501,6 +1709,21 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -1542,6 +1765,48 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "naga" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bf919621e7975acb27d881bae2fb993e0d45c8e0446e85e6272971e00dc8df" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags", + "cfg-if", + "cfg_aliases", + "codespan-reporting", + "half", + "hashbrown 0.16.1", + "hexf-parse", + "indexmap 2.13.0", + "libm", + "log", + "num-traits", + "once_cell", + "rustc-hash 1.1.0", + "spirv", + "thiserror 2.0.18", + "unicode-ident", +] + +[[package]] +name = "nano-rspow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89a9a489674b6761a2d416400e992d9c56f5cb935ec525ffe4e0cfca70cc2d0" +dependencies = [ + "blake2b_simd", + "bytemuck", + "hex", + "pollster", + "rand 0.9.2", + "rayon", + "thiserror 2.0.18", + "wgpu", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -1574,6 +1839,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", ] [[package]] @@ -1594,6 +1922,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + [[package]] name = "ows-cli" version = "1.3.2" @@ -1638,6 +1975,7 @@ dependencies = [ "getrandom 0.2.17", "hex", "k256", + "nano-rspow", "ows-core", "ows-signer", "prost", @@ -1702,6 +2040,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + [[package]] name = "password-hash" version = "0.5.0" @@ -1771,6 +2132,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pollster" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" + [[package]] name = "polyval" version = "0.6.2" @@ -1783,6 +2150,21 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -1807,6 +2189,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + [[package]] name = "prettyplease" version = "0.2.37" @@ -1826,6 +2214,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" + [[package]] name = "proptest" version = "1.11.0" @@ -1875,7 +2269,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.2", "rustls", "socket2 0.6.3", "thiserror 2.0.18", @@ -1895,7 +2289,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.2", "rustls", "rustls-pki-types", "slab", @@ -2023,6 +2417,59 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + [[package]] name = "ref-cast" version = "1.0.25" @@ -2068,6 +2515,12 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + [[package]] name = "reqwest" version = "0.12.28" @@ -2172,6 +2625,12 @@ dependencies = [ "wasm-bindgen", ] +[[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" @@ -2280,6 +2739,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "scrypt" version = "0.11.0" @@ -2526,6 +2991,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spirv" +version = "0.4.0+sdk-1.4.341.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" +dependencies = [ + "bitflags", +] + [[package]] name = "spki" version = "0.7.3" @@ -2542,6 +3016,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.11.1" @@ -2960,6 +3440,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -3175,6 +3661,168 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "wgpu" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e8840e1ba2881d4cbb18d2147627a56af426ff064c0401eb0c8410c6325d07" +dependencies = [ + "arrayvec", + "bitflags", + "bytemuck", + "cfg-if", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "log", + "portable-atomic", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f519832254e56965a9940c4af57dcb75f702b6f6fa4a0b172f685395843a4d7" +dependencies = [ + "arrayvec", + "bit-set", + "bit-vec", + "bitflags", + "bytemuck", + "cfg_aliases", + "document-features", + "hashbrown 0.16.1", + "indexmap 2.13.0", + "log", + "naga", + "once_cell", + "parking_lot", + "portable-atomic", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-core-deps-apple", + "wgpu-core-deps-windows-linux-android", + "wgpu-hal", + "wgpu-naga-bridge", + "wgpu-types", +] + +[[package]] +name = "wgpu-core-deps-apple" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e39e26c4c0e07589e67d18546cf79ff45383659fc72fca4dd293358a0347f3" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-core-deps-windows-linux-android" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e592c1bbef6ad047647ae6e666ebd8cee7a32bb4544d9700ec96cbf73230257" +dependencies = [ + "wgpu-hal", +] + +[[package]] +name = "wgpu-hal" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ace1c17727311c22a46e4e3faf56ea6de81af99dcc839bdfb54857b94d448d" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags", + "block2", + "bytemuck", + "cfg-if", + "cfg_aliases", + "gpu-allocator", + "gpu-descriptor", + "hashbrown 0.16.1", + "libc", + "libloading", + "log", + "naga", + "objc2", + "objc2-core-foundation", + "objc2-foundation", + "objc2-metal", + "objc2-quartz-core", + "once_cell", + "ordered-float", + "parking_lot", + "portable-atomic", + "portable-atomic-util", + "profiling", + "range-alloc", + "raw-window-handle", + "raw-window-metal", + "renderdoc-sys", + "smallvec", + "thiserror 2.0.18", + "wgpu-naga-bridge", + "wgpu-types", + "windows", + "windows-core", +] + +[[package]] +name = "wgpu-naga-bridge" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95226013f547544b223281cd16a4fb549aa9dcb562adbda0faae4c73ffbbc161" +dependencies = [ + "naga", + "wgpu-types", +] + +[[package]] +name = "wgpu-types" +version = "29.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bf84cd9ca8ca45e2b223a3868f1adf9bfc0c66aeac212e76ee7e40fdadf8f5" +dependencies = [ + "bitflags", + "bytemuck", + "log", + "raw-window-handle", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -3188,6 +3836,17 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -3216,6 +3875,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -3303,6 +3972,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" diff --git a/ows/crates/ows-lib/Cargo.toml b/ows/crates/ows-lib/Cargo.toml index 7eadda894..20789dfae 100644 --- a/ows/crates/ows-lib/Cargo.toml +++ b/ows/crates/ows-lib/Cargo.toml @@ -8,8 +8,9 @@ repository = "https://github.com/open-wallet-standard/core" readme = "README.md" [features] -default = [] +default = ["local-pow"] fast-kdf = ["ows-signer/fast-kdf"] +local-pow = ["nano-rspow"] [dependencies] ows-core = { path = "../ows-core", version = "=1.3.2" } @@ -28,6 +29,7 @@ rand = "0.8" prost = "0.13" tonic = { version = "0.12", features = ["transport"] } tokio = { version = "1", features = ["rt"] } +nano-rspow = { version = "0.10", optional = true } [dev-dependencies] tempfile = "3" diff --git a/ows/crates/ows-lib/src/nano_rpc.rs b/ows/crates/ows-lib/src/nano_rpc.rs index 6bbe7f3eb..5d59da539 100644 --- a/ows/crates/ows-lib/src/nano_rpc.rs +++ b/ows/crates/ows-lib/src/nano_rpc.rs @@ -1,6 +1,9 @@ //! Nano RPC helpers (account_info, work_generate, process). //! //! Uses `curl` for HTTP, consistent with the rest of ows-lib (no added HTTP deps). +//! +//! PoW is local-first when recommended (via `nano-rspow`), falling back to remote RPC. +//! Control via `NANO_WORK_MODE` env: `"auto"` (default), `"local"`, `"remote"`, `"retune"`. use crate::error::OwsLibError; use std::process::Command; @@ -105,12 +108,12 @@ pub fn account_info(rpc_url: &str, account: &str) -> Result Result { let body = serde_json::json!({ "action": "work_generate", "hash": hash, - "difficulty": difficulty + "difficulty": difficulty_hex }); let resp = nano_rpc_call(rpc_url, &body)?; @@ -121,38 +124,211 @@ fn work_generate_single( .ok_or_else(|| OwsLibError::BroadcastFailed("no work in work_generate response".into())) } -/// Default PoW fallback endpoint, tried when the primary RPC fails work_generate. -const FALLBACK_WORK_URL: &str = "https://rpc.nano.to"; +/// PoW mode controlled by `NANO_WORK_MODE` env var. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum PowMode { + /// Local only — fail if local PoW can't produce a result. + Local, + /// Remote only — skip local, go straight to RPC. + Remote, + /// Local first, remote fallback on failure. + Auto, + /// Clear local tuning cache, then behave like auto. + Retune, +} -/// Request proof-of-work with multi-endpoint fallback. -/// -/// Tries endpoints in order: -/// 1. The primary `rpc_url` -/// 2. URLs from `NANO_WORK_URL` env var (semicolon-separated URLs) -/// 3. Built-in fallback endpoint +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum LocalPowRecommendation { + Skip, + CheckCachedRecommendation, + ClearCacheAndCheckRecommendation, +} + +fn pow_mode() -> PowMode { + pow_mode_from_env(std::env::var("NANO_WORK_MODE").ok().as_deref()) +} + +fn pow_mode_from_env(value: Option<&str>) -> PowMode { + match value { + Some("local") => PowMode::Local, + Some("remote") => PowMode::Remote, + Some("retune") => PowMode::Retune, + _ => PowMode::Auto, + } +} + +fn local_pow_recommendation_for_mode(mode: PowMode) -> LocalPowRecommendation { + match mode { + PowMode::Auto => LocalPowRecommendation::CheckCachedRecommendation, + PowMode::Retune => LocalPowRecommendation::ClearCacheAndCheckRecommendation, + PowMode::Local | PowMode::Remote => LocalPowRecommendation::Skip, + } +} + +/// Try local PoW via `nano-rspow`. +#[cfg(feature = "local-pow")] +fn work_generate_local(hash_hex: &str, threshold: u64) -> Result { + let hash_bytes = hex::decode(hash_hex).map_err(|e| { + OwsLibError::BroadcastFailed(format!("invalid hash hex for local PoW: {e}")) + })?; + if hash_bytes.len() != 32 { + return Err(OwsLibError::BroadcastFailed(format!( + "hash must be 32 bytes for PoW, got {}", + hash_bytes.len() + ))); + } + let hash: [u8; 32] = hash_bytes.try_into().unwrap(); + + match nano_rspow::work_generate(&hash, threshold) { + Some(result) => Ok(result.nonce_hex()), + None => Err(OwsLibError::BroadcastFailed( + "local PoW generation failed".into(), + )), + } +} + +#[cfg(not(feature = "local-pow"))] +fn work_generate_local(_hash_hex: &str, _threshold: u64) -> Result { + Err(OwsLibError::BroadcastFailed( + "local PoW not available (enable `local-pow` feature)".into(), + )) +} + +/// Returns whether OWS should prefer local Nano PoW on this machine. /// -/// All remote errors are collected and logged to stderr. If every remote fails -/// and `NANO_CPU_POW=1` is set, a future CPU fallback would go here. -pub fn work_generate(rpc_url: &str, hash: &str, difficulty: &str) -> Result { +/// With the `local-pow` feature enabled this delegates to `nano-rspow` and may +/// use its persistent tuning cache. Without local PoW support, it always returns +/// `false`. +#[cfg(feature = "local-pow")] +fn local_pow_recommended() -> bool { + nano_rspow::recommend_local_pow() +} + +#[cfg(not(feature = "local-pow"))] +fn local_pow_recommended() -> bool { + false +} + +#[cfg(feature = "local-pow")] +fn clear_pow_tuning_cache() -> bool { + nano_rspow::clear_pow_tuning_cache() +} + +#[cfg(not(feature = "local-pow"))] +fn clear_pow_tuning_cache() -> bool { + false +} + +fn should_try_local_pow(mode: PowMode) -> bool { + match local_pow_recommendation_for_mode(mode) { + LocalPowRecommendation::CheckCachedRecommendation => local_pow_recommended(), + LocalPowRecommendation::ClearCacheAndCheckRecommendation => { + clear_pow_tuning_cache(); + local_pow_recommended() + } + LocalPowRecommendation::Skip => false, + } +} + +fn parse_difficulty_hex(difficulty_hex: &str) -> Result { + let trimmed = difficulty_hex.trim(); + let hex = trimmed + .strip_prefix("0x") + .or_else(|| trimmed.strip_prefix("0X")) + .unwrap_or(trimmed); + + if hex.is_empty() || hex.len() > 16 { + return Err(OwsLibError::InvalidInput(format!( + "Nano PoW difficulty must be 1-16 hex digits, got {difficulty_hex:?}" + ))); + } + + u64::from_str_radix(hex, 16).map_err(|e| { + OwsLibError::InvalidInput(format!( + "invalid Nano PoW difficulty {difficulty_hex:?}: {e}" + )) + }) +} + +fn configured_work_urls(rpc_url: &str) -> Vec { + parse_work_urls(rpc_url, std::env::var("NANO_WORK_URL").ok().as_deref()) +} + +fn parse_work_urls(rpc_url: &str, urls: Option<&str>) -> Vec { let mut endpoints: Vec = vec![rpc_url.to_string()]; - if let Ok(urls) = std::env::var("NANO_WORK_URL") { - for url in urls.split(';') { + if let Some(urls) = urls { + for url in urls.split([';', ',']) { let url = url.trim(); - if !url.is_empty() && url != rpc_url { + if !url.is_empty() && !endpoints.iter().any(|endpoint| endpoint == url) { endpoints.push(url.to_string()); } } } - if !endpoints.iter().any(|e| e == FALLBACK_WORK_URL) { - endpoints.push(FALLBACK_WORK_URL.to_string()); + endpoints +} + +/// Request proof-of-work using a Nano RPC difficulty hex string. +/// +/// Controlled by `NANO_WORK_MODE` env var: +/// - `"auto"` (default): local when recommended, remote otherwise +/// - `"local"`: local PoW only, fail if it can't produce a result +/// - `"remote"`: remote RPC only, skip local +/// - `"retune"`: clear the local tuning cache, then behave like auto +/// +/// Remote endpoints are tried in order: +/// 1. The primary `rpc_url` +/// 2. URLs from `NANO_WORK_URL` env var (semicolon- or comma-separated) +pub fn work_generate( + rpc_url: &str, + hash: &str, + difficulty_hex: &str, +) -> Result { + let threshold = parse_difficulty_hex(difficulty_hex)?; + work_generate_threshold(rpc_url, hash, threshold) +} + +/// Request proof-of-work using a numeric threshold. +/// +/// This helper is intended for internal OWS code that already deals in +/// `nano-rspow` threshold constants. +pub fn work_generate_threshold( + rpc_url: &str, + hash: &str, + threshold: u64, +) -> Result { + let mode = pow_mode(); + match mode { + PowMode::Remote => { + return work_generate_remote(rpc_url, hash, threshold); + } + PowMode::Local => { + return work_generate_local(hash, threshold); + } + PowMode::Auto | PowMode::Retune => {} } + if should_try_local_pow(mode) { + if let Ok(work) = work_generate_local(hash, threshold) { + return Ok(work); + } + + eprintln!(" Local PoW failed, falling back to remote"); + } + + work_generate_remote(rpc_url, hash, threshold) +} + +/// Remote PoW fallback — tries the primary RPC then `NANO_WORK_URL` endpoints. +fn work_generate_remote(rpc_url: &str, hash: &str, threshold: u64) -> Result { + let difficulty_hex = format!("{:016x}", threshold); + let endpoints = configured_work_urls(rpc_url); + let mut last_error = None; for endpoint in &endpoints { - match work_generate_single(endpoint, hash, difficulty) { + match work_generate_single(endpoint, hash, &difficulty_hex) { Ok(work) => return Ok(work), Err(e) => { eprintln!(" PoW failed on {endpoint}: {e}"); @@ -188,6 +364,131 @@ pub fn process_block( .ok_or_else(|| OwsLibError::BroadcastFailed(format!("no hash in process response: {resp}"))) } -/// PoW difficulty thresholds (as hex strings for work_generate RPC). -pub const SEND_DIFFICULTY: &str = "fffffff800000000"; -pub const RECEIVE_DIFFICULTY: &str = "fffffe0000000000"; +/// Epoch 2 send/change threshold. +/// +/// When the `local-pow` feature is enabled, sourced directly from +/// `nano_rspow::thresholds` to avoid any duplication. When disabled, +/// falls back to the same hard-coded value. +#[cfg(feature = "local-pow")] +pub use nano_rspow::thresholds::EPOCH2_SEND; + +#[cfg(not(feature = "local-pow"))] +pub const EPOCH2_SEND: u64 = 0xffff_fff8_0000_0000; + +/// Epoch 2 receive threshold. +#[cfg(feature = "local-pow")] +pub use nano_rspow::thresholds::EPOCH2_RECEIVE; + +#[cfg(not(feature = "local-pow"))] +pub const EPOCH2_RECEIVE: u64 = 0xffff_fe00_0000_0000; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn epoch2_send_hex_matches_expected() { + let hex = format!("{:016x}", EPOCH2_SEND); + assert_eq!(hex, "fffffff800000000"); + } + + #[test] + fn epoch2_receive_hex_matches_expected() { + let hex = format!("{:016x}", EPOCH2_RECEIVE); + assert_eq!(hex, "fffffe0000000000"); + } + + #[test] + fn threshold_hex_roundtrip() { + for threshold in [EPOCH2_SEND, EPOCH2_RECEIVE] { + let hex = format!("{:016x}", threshold); + let decoded = u64::from_str_radix(&hex, 16).unwrap(); + assert_eq!(decoded, threshold); + } + } + + #[test] + fn parse_difficulty_accepts_plain_and_prefixed_hex() { + assert_eq!( + parse_difficulty_hex("fffffff800000000").unwrap(), + EPOCH2_SEND + ); + assert_eq!( + parse_difficulty_hex("0xfffffe0000000000").unwrap(), + EPOCH2_RECEIVE + ); + } + + #[test] + fn parse_difficulty_rejects_invalid_hex() { + assert!(parse_difficulty_hex("").is_err()); + assert!(parse_difficulty_hex("10000000000000000").is_err()); + assert!(parse_difficulty_hex("not-hex").is_err()); + } + + #[test] + fn pow_mode_from_env_accepts_canonical_modes() { + assert_eq!(pow_mode_from_env(Some("local")), PowMode::Local); + assert_eq!(pow_mode_from_env(Some("remote")), PowMode::Remote); + assert_eq!(pow_mode_from_env(Some("auto")), PowMode::Auto); + assert_eq!(pow_mode_from_env(Some("retune")), PowMode::Retune); + assert_eq!(pow_mode_from_env(Some("unexpected")), PowMode::Auto); + assert_eq!(pow_mode_from_env(None), PowMode::Auto); + } + + #[test] + fn pow_mode_recommendation_action_matches_modes() { + assert_eq!( + local_pow_recommendation_for_mode(PowMode::Auto), + LocalPowRecommendation::CheckCachedRecommendation + ); + assert_eq!( + local_pow_recommendation_for_mode(PowMode::Retune), + LocalPowRecommendation::ClearCacheAndCheckRecommendation + ); + assert_eq!( + local_pow_recommendation_for_mode(PowMode::Local), + LocalPowRecommendation::Skip + ); + assert_eq!( + local_pow_recommendation_for_mode(PowMode::Remote), + LocalPowRecommendation::Skip + ); + } + + #[test] + fn parse_work_urls_accepts_semicolon_and_comma() { + assert_eq!( + parse_work_urls("https://primary", Some("https://a; https://b,https://c")), + vec![ + "https://primary".to_string(), + "https://a".to_string(), + "https://b".to_string(), + "https://c".to_string() + ] + ); + } + + #[test] + fn parse_work_urls_skips_empty_and_duplicate_endpoints() { + assert_eq!( + parse_work_urls( + "https://primary", + Some(" ;https://a,https://primary;https://a") + ), + vec!["https://primary".to_string(), "https://a".to_string()] + ); + } + + #[cfg(feature = "local-pow")] + #[test] + fn local_pow_known_test_vector() { + let hash_bytes = + hex::decode("718CC2121C3E641059BC1C2CFC45666C99E8AE922F7A807B7D07B62C995D79E2") + .unwrap(); + let hash: [u8; 32] = hash_bytes.try_into().unwrap(); + let work = u64::from_str_radix("2bf29ef00786a6bc", 16).unwrap(); + let result = nano_rspow::work_validate(&hash, work, nano_rspow::thresholds::EPOCH1); + assert!(result.is_valid(), "result should meet the threshold"); + } +} diff --git a/ows/crates/ows-lib/src/ops.rs b/ows/crates/ows-lib/src/ops.rs index 92be1b6e1..d646ac0c9 100644 --- a/ows/crates/ows-lib/src/ops.rs +++ b/ows/crates/ows-lib/src/ops.rs @@ -1019,9 +1019,9 @@ fn broadcast_nano(rpc_url: &str, signed_bytes: &[u8]) -> Result crate::nano_rpc::SEND_DIFFICULTY, - _ => crate::nano_rpc::RECEIVE_DIFFICULTY, + let threshold = match subtype { + "send" => crate::nano_rpc::EPOCH2_SEND, + _ => crate::nano_rpc::EPOCH2_RECEIVE, }; // PoW root: for open blocks, use account pubkey; otherwise use previous hash @@ -1031,7 +1031,7 @@ fn broadcast_nano(rpc_url: &str, signed_bytes: &[u8]) -> Result