diff --git a/Cargo.lock b/Cargo.lock index 7d67ad17..2539eabb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,7 +67,7 @@ dependencies = [ "amplify_num", "amplify_syn", "ascii", - "rand 0.8.5", + "rand 0.8.6", "serde", "stringly_conversions", "wasm-bindgen", @@ -268,9 +268,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ "aws-lc-sys", "zeroize", @@ -278,9 +278,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.39.1" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" dependencies = [ "cc", "cmake", @@ -581,7 +581,7 @@ dependencies = [ "pkcs8 0.9.0", "prost", "prost-types", - "rand 0.8.5", + "rand 0.8.6", "rand_core 0.6.4", "regex", "serde_json", @@ -684,25 +684,25 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] [[package]] name = "blake3" -version = "1.8.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "cpufeatures 0.2.17", + "cpufeatures 0.3.0", ] [[package]] @@ -767,9 +767,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.58" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -814,7 +814,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -863,9 +863,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -885,9 +885,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -947,6 +947,16 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -1362,7 +1372,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls 0.23.37", + "rustls 0.23.38", "serde", "serde_json", "webpki-roots 0.25.4", @@ -1379,7 +1389,7 @@ dependencies = [ "byteorder", "libc", "log", - "rustls 0.23.37", + "rustls 0.23.38", "serde", "serde_json", "webpki-roots 0.25.4", @@ -1485,9 +1495,9 @@ checksum = "a35a73237400bde66c82e38387343f90d7182a2f2f22729e096a2abd57d75db9" [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "ff" @@ -1732,7 +1742,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -1754,6 +1764,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.7.1" @@ -1794,9 +1823,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "hashlink" @@ -1929,21 +1958,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", + "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1951,15 +1980,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.37", - "rustls-pki-types", + "rustls 0.23.38", "tokio", "tokio-rustls", "tower-service", @@ -1999,9 +2027,11 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -2030,12 +2060,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -2043,9 +2074,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -2056,9 +2087,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -2070,15 +2101,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -2090,15 +2121,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -2144,12 +2175,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -2183,9 +2214,9 @@ checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -2279,9 +2310,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.92" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "cfg-if", "futures-util", @@ -2306,9 +2337,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.183" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libm" @@ -2318,14 +2349,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "bitflags", "libc", "plain", - "redox_syscall 0.7.3", + "redox_syscall 0.7.4", ] [[package]] @@ -2487,9 +2518,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -2512,6 +2543,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "mac_address" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" +dependencies = [ + "nix", + "serde", + "winapi", +] + [[package]] name = "magic-crypt" version = "4.0.1" @@ -2559,6 +2601,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -2665,6 +2716,19 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -2714,7 +2778,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] @@ -2775,9 +2839,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" dependencies = [ "bitflags", "cfg-if", @@ -2805,14 +2869,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-src" +version = "300.6.0+3.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -2967,12 +3041,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkcs1" version = "0.7.5" @@ -3006,9 +3074,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -3036,9 +3104,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -3166,7 +3234,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.37", + "rustls 0.23.38", "socket2", "thiserror 2.0.18", "tokio", @@ -3184,10 +3252,10 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", - "rustls 0.23.37", + "rustls 0.23.38", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -3233,9 +3301,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -3244,9 +3312,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -3254,13 +3322,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20 0.10.0", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -3303,9 +3371,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "redox_syscall" @@ -3318,9 +3386,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" dependencies = [ "bitflags", ] @@ -3433,28 +3501,34 @@ checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "js-sys", "log", + "mime", "mime_guess", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.37", + "rustls 0.23.38", "rustls-pki-types", "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", + "tokio-native-tls", "tokio-rustls", "tower", "tower-http", @@ -3525,7 +3599,7 @@ dependencies = [ "getrandom 0.3.4", "hex-conservative 0.2.2", "mime", - "rand 0.9.2", + "rand 0.9.4", "rgb-aluvm", "rgb-strict-encoding", "rgb-strict-types", @@ -3548,7 +3622,7 @@ dependencies = [ "fluent-uri", "indexmap", "percent-encoding", - "rand 0.9.2", + "rand 0.9.4", "rgb-consensus", "rgb-strict-encoding", "rgb-strict-types", @@ -3558,8 +3632,7 @@ dependencies = [ [[package]] name = "rgb-lib" version = "0.3.0-beta.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a09de20d5b52c051897e4d990615fc8110f9efbf1bb43c033cec2dfeddd7691" +source = "git+https://github.com/RGB-Tools/rgb-lib?branch=master#5c62632b5cbc9e5d5852aebf5824659b0b501c78" dependencies = [ "amplify", "base64 0.22.1", @@ -3570,7 +3643,7 @@ dependencies = [ "file-format", "generic-array", "hex", - "rand 0.10.0", + "rand 0.10.1", "reqwest 0.13.2", "rgb-invoicing", "rgb-lib-migration", @@ -3579,7 +3652,7 @@ dependencies = [ "rgb-schemas", "rgb-strict-encoding", "rgb-strict-types", - "rustls 0.23.37", + "rustls 0.23.38", "scrypt", "sea-orm", "sea-query", @@ -3595,14 +3668,13 @@ dependencies = [ "typenum", "url", "walkdir", - "zip 8.4.0", + "zip 8.5.1", ] [[package]] name = "rgb-lib-migration" version = "0.3.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4dd5262d25fe54dd65afa13c19859abba7f81d130fa26d10f018e30bfdd333a" +source = "git+https://github.com/RGB-Tools/rgb-lib?branch=master#5c62632b5cbc9e5d5852aebf5824659b0b501c78" dependencies = [ "sea-orm-migration", "tokio", @@ -3629,6 +3701,7 @@ dependencies = [ "electrum-client 0.20.0", "futures", "hex-conservative 0.3.2", + "http", "lazy_static", "lightning", "lightning-background-processor", @@ -3641,7 +3714,7 @@ dependencies = [ "lightning-rapid-gossip-sync", "magic-crypt", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "regex", "reqwest 0.12.28", "rgb-lib", @@ -3680,7 +3753,7 @@ dependencies = [ "getrandom 0.3.4", "indexmap", "nonasync", - "rand 0.9.2", + "rand 0.9.4", "rgb-aluvm", "rgb-ascii-armor", "rgb-consensus", @@ -3860,16 +3933,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.10", + "rustls-webpki 0.103.12", "subtle", "zeroize", ] @@ -3902,15 +3975,15 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.23.37", + "rustls 0.23.38", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.10", + "rustls-webpki 0.103.12", "security-framework", "security-framework-sys", "webpki-root-certs", @@ -3935,9 +4008,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" dependencies = [ "aws-lc-rs", "ring", @@ -4042,9 +4115,9 @@ dependencies = [ [[package]] name = "sea-orm" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d945f62558fac19e5988680d2fdf747b734c2dbc6ce2cb81ba33ed8dde5b103" +checksum = "2dc312fedd460a47ea563911761d254a84e7b51d8cc73ec92c929e78f33fa957" dependencies = [ "async-stream", "async-trait", @@ -4053,6 +4126,7 @@ dependencies = [ "derive_more", "futures-util", "log", + "mac_address", "ouroboros", "pgvector", "rust_decimal", @@ -4072,9 +4146,9 @@ dependencies = [ [[package]] name = "sea-orm-cli" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94492e2ab6c045b4cc38013809ce255d14c3d352c9f0d11e6b920e2adc948ad" +checksum = "da80ebcdb44571e86f03a2bdcb5532136a87397f366f38bbce64673fc5e6a450" dependencies = [ "chrono", "clap", @@ -4091,9 +4165,9 @@ dependencies = [ [[package]] name = "sea-orm-macros" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c2e64a50a9cc8339f10a27577e10062c7f995488e469f2c95762c5ee847832" +checksum = "9b9a3f90e336ec74803e8eb98c61bc98754c1adfba3b4f84d946237b752b1c88" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -4105,9 +4179,9 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7315c0cadb7e60fb17ee2bb282aa27d01911fc2a7e5836ec1d4ac37d19250bb4" +checksum = "07c577f2959277e936c1d08109acd1e08fc36a95ef29ec028190ba82cad8f96e" dependencies = [ "async-trait", "clap", @@ -4203,7 +4277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes", - "rand 0.8.5", + "rand 0.8.6", "secp256k1-sys", "serde", ] @@ -4224,7 +4298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -4242,9 +4316,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -4578,7 +4652,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rustls 0.23.37", + "rustls 0.23.38", "serde", "serde_json", "sha2 0.10.9", @@ -4658,7 +4732,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "sha1", @@ -4696,7 +4770,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_json", "sha2 0.10.9", @@ -4783,6 +4857,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -4825,6 +4905,27 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -4944,9 +5045,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -4969,9 +5070,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -4985,9 +5086,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -5010,7 +5111,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.37", + "rustls 0.23.38", "tokio", ] @@ -5141,11 +5242,12 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", + "symlink", "thiserror 2.0.18", "time", "tracing-subscriber", @@ -5236,9 +5338,9 @@ checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "unicase" @@ -5327,9 +5429,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "serde_core", @@ -5380,11 +5482,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -5393,7 +5495,7 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] @@ -5404,9 +5506,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -5418,9 +5520,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.65" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ "js-sys", "wasm-bindgen", @@ -5428,9 +5530,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5438,9 +5540,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -5451,9 +5553,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.115" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -5507,9 +5609,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.92" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -5527,9 +5629,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] @@ -5546,14 +5648,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.6", + "webpki-roots 1.0.7", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -5640,6 +5742,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.4.1" @@ -5964,6 +6077,12 @@ 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" @@ -6045,9 +6164,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yansi" @@ -6057,9 +6176,9 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -6068,9 +6187,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -6080,18 +6199,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.47" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -6100,18 +6219,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -6127,9 +6246,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -6138,9 +6257,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -6149,9 +6268,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -6177,9 +6296,9 @@ dependencies = [ [[package]] name = "zip" -version = "8.4.0" +version = "8.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7756d0206d058333667493c4014f545f4b9603c4330ccd6d9b3f86dcab59f7d9" +checksum = "dcab981e19633ebcf0b001ddd37dd802996098bc1864f90b7c5d970ce76c1d59" dependencies = [ "crc32fast", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index 0a1abd20..fed84e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,9 @@ zip = { version = "2.2.0", default-features = false, features = ["time", "zstd"] [dev-dependencies] dircmp = "0.2.0" electrum-client = "0.20.0" +http = "1.4.0" lazy_static = { version = "1.5.0", default-features = false } +lightning = { version = "0.2.0", path = "./rust-lightning/lightning", features = ["_rln_test_hooks"] } once_cell = "1.20.0" reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "native-tls", "stream"] } serial_test = "3.1.1" @@ -69,6 +71,7 @@ tracing-test = "0.2.5" [patch.crates-io] lightning = { path = "./rust-lightning/lightning" } lightning-background-processor = { path = "./rust-lightning/lightning-background-processor"} +rgb-lib = { git = "https://github.com/RGB-Tools/rgb-lib", branch = "master" } [lints.rust.unexpected_cfgs] level = "allow" diff --git a/openapi.yaml b/openapi.yaml index acb344b0..32e674d7 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3014,7 +3014,8 @@ components: - RgbSend - Drain - CreateUtxos - - User + - SendBtc + - Incoming Transfer: type: object required: diff --git a/rust-lightning b/rust-lightning index bfc31eab..4a08199e 160000 --- a/rust-lightning +++ b/rust-lightning @@ -1 +1 @@ -Subproject commit bfc31eabaf96f8c325f32a41023df55a3d7cbebd +Subproject commit 4a08199e3ad3b2426cd2269f000b0715455655a9 diff --git a/src/backup.rs b/src/backup.rs index a5b8123c..ceef6712 100644 --- a/src/backup.rs +++ b/src/backup.rs @@ -52,8 +52,8 @@ pub(crate) fn do_backup( if backup_file.exists() { Err(APIError::InvalidBackupPath)?; } - let tmp_base_path = _get_parent_path(backup_file)?; - let files = _get_backup_paths(&tmp_base_path)?; + let tmp_base_path = get_parent_path(backup_file)?; + let files = get_backup_paths(&tmp_base_path)?; let salt: String = rand::thread_rng() .sample_iter(&Alphanumeric) .take(BACKUP_KEY_LENGTH) @@ -69,18 +69,18 @@ pub(crate) fn do_backup( // create zip archive of wallet data tracing::debug!("\nzipping {:?} to {:?}", &wallet_dir, &files.zip); - _zip_dir(wallet_dir, &files.zip)?; + zip_dir(wallet_dir, &files.zip)?; // encrypt the backup file tracing::debug!("\nencrypting {:?} to {:?}", &files.zip, &files.encrypted); - _encrypt_file(&files.zip, &files.encrypted, password, &salt, &nonce)?; + encrypt_file(&files.zip, &files.encrypted, password, &salt, &nonce)?; // add backup nonce + salt + version to final zip file write(files.nonce, nonce)?; write(files.salt, salt)?; write(files.version, BACKUP_VERSION.to_string())?; tracing::debug!("\nzipping {:?} to {:?}", &files.tempdir, &backup_file); - _zip_dir(files.tempdir.path(), backup_file)?; + zip_dir(files.tempdir.path(), backup_file)?; tracing::info!("backup completed"); Ok(()) @@ -95,13 +95,13 @@ pub(crate) fn restore_backup( // setup tracing::info!("starting restore..."); let backup_file = PathBuf::from(backup_path); - let tmp_base_path = _get_parent_path(&backup_file)?; - let files = _get_backup_paths(&tmp_base_path)?; + let tmp_base_path = get_parent_path(&backup_file)?; + let files = get_backup_paths(&tmp_base_path)?; let target_dir_path = PathBuf::from(&target_dir); // unpack given zip file and retrieve backup data tracing::info!("unzipping {:?}", backup_file); - _unzip(&backup_file, &PathBuf::from(files.tempdir.path()))?; + unzip(&backup_file, &PathBuf::from(files.tempdir.path()))?; let nonce = read_to_string(files.nonce)?; tracing::debug!("using retrieved nonce: {}", &nonce); let salt = read_to_string(files.salt)?; @@ -118,15 +118,15 @@ pub(crate) fn restore_backup( // decrypt backup and restore files tracing::info!("decrypting {:?} to {:?}", files.encrypted, files.zip); - _decrypt_file(&files.encrypted, &files.zip, password, &salt, &nonce)?; + decrypt_file(&files.encrypted, &files.zip, password, &salt, &nonce)?; tracing::info!("unzipping {:?} to {:?}", &files.zip, &target_dir_path); - _unzip(&files.zip, &target_dir_path)?; + unzip(&files.zip, &target_dir_path)?; tracing::info!("restore completed"); Ok(()) } -fn _get_backup_paths(tmp_base_path: &Path) -> Result { +fn get_backup_paths(tmp_base_path: &Path) -> Result { create_dir_all(tmp_base_path)?; let tempdir = tempfile::tempdir_in(tmp_base_path)?; let encrypted = tempdir.path().join("backup.enc"); @@ -144,7 +144,7 @@ fn _get_backup_paths(tmp_base_path: &Path) -> Result { }) } -fn _get_parent_path(file: &Path) -> Result { +fn get_parent_path(file: &Path) -> Result { if let Some(parent) = file.parent() { Ok(parent.to_path_buf()) } else { @@ -152,7 +152,7 @@ fn _get_parent_path(file: &Path) -> Result { } } -fn _zip_dir(path_in: &Path, path_out: &Path) -> Result<(), APIError> { +fn zip_dir(path_in: &Path, path_out: &Path) -> Result<(), APIError> { // setup let writer = File::create(path_out)?; let mut zip = zip::ZipWriter::new(writer); @@ -207,7 +207,7 @@ fn _zip_dir(path_in: &Path, path_out: &Path) -> Result<(), APIError> { Ok(()) } -fn _unzip(zip_path: &PathBuf, path_out: &Path) -> Result<(), APIError> { +fn unzip(zip_path: &PathBuf, path_out: &Path) -> Result<(), APIError> { // setup let file = File::open(zip_path).map_err(|e| APIError::Unexpected(format!("Failed to unzip: {e}")))?; @@ -246,7 +246,7 @@ fn _unzip(zip_path: &PathBuf, path_out: &Path) -> Result<(), APIError> { Ok(()) } -fn _get_cypher_secrets( +fn get_cypher_secrets( password: &str, salt_str: &str, nonce_str: &str, @@ -275,14 +275,14 @@ fn _get_cypher_secrets( Ok(CypherSecrets { key, nonce }) } -fn _encrypt_file( +fn encrypt_file( path_cleartext: &PathBuf, path_encrypted: &PathBuf, password: &str, salt_str: &str, nonce_str: &str, ) -> Result<(), APIError> { - let cypher_secrets = _get_cypher_secrets(password, salt_str, nonce_str)?; + let cypher_secrets = get_cypher_secrets(password, salt_str, nonce_str)?; // - XChacha20Poly1305 is fast, requires no special hardware and supports stream operation // - stream mode required as files to encrypt may be big, so avoiding a memory buffer @@ -318,14 +318,14 @@ fn _encrypt_file( Ok(()) } -fn _decrypt_file( +fn decrypt_file( path_encrypted: &PathBuf, path_cleartext: &PathBuf, password: &str, salt_str: &str, nonce_str: &str, ) -> Result<(), APIError> { - let cypher_secrets = _get_cypher_secrets(password, salt_str, nonce_str)?; + let cypher_secrets = get_cypher_secrets(password, salt_str, nonce_str)?; // setup let aead = XChaCha20Poly1305::new(&cypher_secrets.key); diff --git a/src/error.rs b/src/error.rs index 7c8fe7a7..fd32d4af 100644 --- a/src/error.rs +++ b/src/error.rs @@ -98,7 +98,7 @@ pub enum APIError { #[error("Insufficient capacity to cover the commitment transaction fees ({0} sat)")] InsufficientCapacity(u64), - #[error("Not enough funds, get an address and send {0} sats there")] + #[error("Not enough funds, missing {0} sats")] InsufficientFunds(u64), #[error("Invalid address: {0}")] @@ -260,9 +260,6 @@ pub enum APIError { #[error("No valid transport endpoint found")] NoValidTransportEndpoint, - #[error("Cannot perform this operation while an open channel operation is in progress")] - OpenChannelInProgress, - #[error("Output below the dust limit")] OutputBelowDustLimit, @@ -517,7 +514,6 @@ impl IntoResponse for APIError { | APIError::NoAvailableUtxos | APIError::NoRoute | APIError::NotInitialized - | APIError::OpenChannelInProgress | APIError::PaymentNotFound(_) | APIError::RecipientIDAlreadyUsed | APIError::SwapNotFound(_) diff --git a/src/ldk.rs b/src/ldk.rs index 9dfd0261..83f719c9 100644 --- a/src/ldk.rs +++ b/src/ldk.rs @@ -1,5 +1,6 @@ use amplify::{map, s}; use bitcoin::blockdata::locktime::absolute::LockTime; +use bitcoin::hex::DisplayHex; use bitcoin::psbt::{ExtractTxError, Psbt}; use bitcoin::secp256k1::{All, PublicKey, Secp256k1}; use bitcoin::{io, Amount, Network}; @@ -23,9 +24,9 @@ use lightning::onion_message::messenger::{ }; use lightning::rgb_utils::{ get_rgb_channel_info_pending, is_channel_rgb, parse_rgb_payment_info, read_rgb_transfer_info, - update_rgb_channel_amount, BITCOIN_NETWORK_FNAME, INDEXER_URL_FNAME, STATIC_BLINDING, - WALLET_ACCOUNT_XPUB_COLORED_FNAME, WALLET_ACCOUNT_XPUB_VANILLA_FNAME, WALLET_FINGERPRINT_FNAME, - WALLET_MASTER_FINGERPRINT_FNAME, + update_rgb_channel_amount, write_rgb_channel_info, BITCOIN_NETWORK_FNAME, INDEXER_URL_FNAME, + STATIC_BLINDING, WALLET_ACCOUNT_XPUB_COLORED_FNAME, WALLET_ACCOUNT_XPUB_VANILLA_FNAME, + WALLET_FINGERPRINT_FNAME, WALLET_MASTER_FINGERPRINT_FNAME, }; use lightning::routing::gossip; use lightning::routing::gossip::{NodeId, P2PGossipSync}; @@ -65,14 +66,15 @@ use rgb_lib::{ secp256k1::Secp256k1 as Secp256k1_30, ScriptBuf, }, + keys::WitnessVersion, utils::{get_account_data, recipient_id_from_script_buf, script_buf_from_recipient_id}, wallet::{ rust_only::{check_indexer_url, AssetColoringInfo, ColoringInfo}, DatabaseType, Recipient, SinglesigKeys, TransportEndpoint, Wallet as RgbLibWallet, WalletData, WitnessData, }, - AssetSchema, Assignment, BitcoinNetwork, ConsignmentExt, ContractId, Fascia, FileContent, - RgbTransfer, RgbTxid, WitnessOrd, + AssetSchema, Assignment, BitcoinNetwork, ConsignmentExt, ContractId, Error as RgbLibError, + Fascia, FileContent, RgbTransfer, RgbTxid, WitnessOrd, }; use std::collections::HashMap; use std::convert::TryInto; @@ -111,6 +113,9 @@ pub(crate) const FEE_RATE: u64 = 7; pub(crate) const UTXO_SIZE_SAT: u32 = 32000; pub(crate) const MIN_CHANNEL_CONFIRMATIONS: u8 = 6; +#[cfg(test)] +pub(crate) static IGNORE_INBOUND_CHANNELS_ON_NODE: Mutex> = Mutex::new(None); + pub(crate) struct LdkBackgroundServices { stop_processing: Arc, peer_manager: Arc, @@ -525,7 +530,7 @@ pub(crate) type OutputSweeper = ldk_sweep::OutputSweeper< Arc, >; -fn _update_rgb_channel_amount(ldk_data_dir: &Path, payment_hash: &PaymentHash, receiver: bool) { +fn find_and_update_rgb_chan_amt(ldk_data_dir: &Path, payment_hash: &PaymentHash, receiver: bool) { let payment_hash_str = hex_str(&payment_hash.0); for entry in fs::read_dir(ldk_data_dir).unwrap() { let file = entry.unwrap(); @@ -553,6 +558,114 @@ fn _update_rgb_channel_amount(ldk_data_dir: &Path, payment_hash: &PaymentHash, r } } +// Handle an rgb-lib error that happened while preparing a channel funding transaction in +// FundingGenerationReady. Returns the value to propagate from the event handler: `Err(ReplayEvent)` +// to retry the event (for transient network errors), or `Ok(())` after force-closing the channel +// (for terminal errors). +fn handle_funding_prepare_err( + e: RgbLibError, + channel_manager: &ChannelManager, + temporary_channel_id: &ChannelId, + counterparty_node_id: &PublicKey, +) -> Result<(), ReplayEvent> { + match e { + RgbLibError::Indexer { details } + | RgbLibError::InvalidIndexer { details } + | RgbLibError::Network { details } => { + tracing::error!("Network error during channel opening: {details}"); + Err(ReplayEvent()) + } + e => { + tracing::error!("Cannot open channel: {e}"); + if let Err(close_err) = channel_manager.force_close_broadcasting_latest_txn( + temporary_channel_id, + counterparty_node_id, + e.to_string(), + ) { + tracing::error!( + "Failed to force-close channel {temporary_channel_id} after error: {close_err:?}" + ); + } + Ok(()) + } + } +} + +async fn handle_open_chan_fail( + channel_id: &ChannelId, + static_state: &StaticState, + unlocked_state: Arc, +) { + tracing::info!("Handling open channel failure for channel {channel_id}"); + let pending_funding_path = static_state + .ldk_data_dir + .join(format!("pending_funding_{}", channel_id.0.as_hex())); + if let Some((rgb_info, _)) = + get_rgb_channel_info_optional(channel_id, &PathBuf::from(&static_state.ldk_data_dir), true) + { + if let Some(batch_transfer_idx) = rgb_info.batch_transfer_idx { + let unlocked_state_copy = unlocked_state.clone(); + let failed = tokio::task::spawn_blocking(move || { + unlocked_state_copy.rgb_fail_transfers(Some(batch_transfer_idx), false, true) + }) + .await + .unwrap(); + match failed { + Ok(changed) => { + tracing::info!( + "RGB transfer batch_transfer_idx={} for channel {}: {}", + batch_transfer_idx, + channel_id, + if changed { + "failed successfully" + } else { + "no change needed" + } + ); + } + Err(e) => { + tracing::error!( + "Error failing RGB transfer batch_transfer_idx={} for channel {}: {:?}", + batch_transfer_idx, + channel_id, + e + ); + } + } + } + } else if pending_funding_path.exists() { + let funding_txid = fs::read_to_string(&pending_funding_path).unwrap(); + let unlocked_state_copy = unlocked_state.clone(); + let txid_copy = funding_txid.clone(); + let result = tokio::task::spawn_blocking(move || { + unlocked_state_copy.rgb_abort_pending_vanilla_tx(txid_copy) + }) + .await + .unwrap(); + match result { + Ok(()) => { + tracing::info!( + "Aborted pending vanilla tx {} for channel {}", + funding_txid, + channel_id + ); + } + Err(e) => { + tracing::error!( + "Error aborting pending vanilla tx {} for channel {}: {:?}", + funding_txid, + channel_id, + e + ); + } + } + } + if pending_funding_path.exists() { + fs::remove_file(&pending_funding_path).unwrap(); + } + unlocked_state.delete_channel_id(*channel_id); +} + async fn handle_ldk_events( event: Event, unlocked_state: Arc, @@ -601,7 +714,8 @@ async fn handle_ldk_events( AssetSchema::Uda => Assignment::NonFungible, }; - let recipient_id = recipient_id_from_script_buf(script_buf, static_state.network); + let recipient_id = + recipient_id_from_script_buf(script_buf.clone(), static_state.network); let recipient_map = map! { asset_id.clone() => vec![Recipient { @@ -615,52 +729,103 @@ async fn handle_ldk_events( }]}; let unlocked_state_copy = unlocked_state.clone(); - let unsigned_psbt = tokio::task::spawn_blocking(move || { - let res = unlocked_state_copy - .rgb_send_begin( - recipient_map, - true, - FEE_RATE, - MIN_CHANNEL_CONFIRMATIONS, - None, - true, - ) - .unwrap(); + let res = tokio::task::spawn_blocking(move || { + let res = unlocked_state_copy.rgb_send_begin( + recipient_map, + true, + FEE_RATE, + MIN_CHANNEL_CONFIRMATIONS, + None, + false, + )?; let fascia_str = fs::read_to_string(&res.details.fascia_path).unwrap(); let fascia: Fascia = serde_json::from_str(&fascia_str).unwrap(); - unlocked_state_copy - .rgb_consume_fascia(fascia, None) - .unwrap(); - unlocked_state_copy - .rgb_create_consignments(res.psbt.clone()) - .unwrap(); - res.psbt + unlocked_state_copy.rgb_consume_fascia(fascia, None)?; + unlocked_state_copy.rgb_create_consignments(res.psbt.clone())?; + Ok((res.psbt, res.batch_transfer_idx)) }) .await .unwrap(); - (unsigned_psbt, Some(asset_id)) + match res { + Err(e) => { + return handle_funding_prepare_err( + e, + &unlocked_state.channel_manager, + &temporary_channel_id, + &counterparty_node_id, + ); + } + Ok((unsigned_psbt, batch_transfer_idx)) => { + if let Some((mut rgb_info, info_path)) = get_rgb_channel_info_optional( + &temporary_channel_id, + &PathBuf::from(&static_state.ldk_data_dir), + true, + ) { + rgb_info.batch_transfer_idx = batch_transfer_idx; + write_rgb_channel_info(&info_path, &rgb_info); + } + (unsigned_psbt, Some(asset_id)) + } + } } else { - let unsigned_psbt = unlocked_state - .rgb_send_btc_begin(addr.to_address(), channel_value_satoshis, FEE_RATE) - .unwrap(); - (unsigned_psbt, None) + let unlocked_state_copy = unlocked_state.clone(); + let btc_address = addr.to_address(); + let res = tokio::task::spawn_blocking(move || { + unlocked_state_copy.rgb_send_btc_begin( + btc_address, + channel_value_satoshis, + FEE_RATE, + false, + ) + }) + .await + .unwrap(); + match res { + Err(e) => { + return handle_funding_prepare_err( + e, + &unlocked_state.channel_manager, + &temporary_channel_id, + &counterparty_node_id, + ); + } + Ok(unsigned_psbt) => (unsigned_psbt, None), + } }; let signed_psbt = unlocked_state.rgb_sign_psbt(unsigned_psbt).unwrap(); let psbt = Psbt::from_str(&signed_psbt).unwrap(); let funding_tx = psbt.clone().extract_tx().unwrap(); - let funding_txid = funding_tx.compute_txid().to_string(); - tracing::info!("Funding TXID: {funding_txid}"); + let funding_txid = funding_tx.compute_txid(); + let funding_txid_str = funding_txid.to_string(); + tracing::info!("Funding TXID: {funding_txid_str}"); + + // persist the funding TXID keyed by the final channel ID so handle_open_chan_fail can + // find it + let funding_output_index = funding_tx + .output + .iter() + .position(|o| o.script_pubkey == script_buf) + .expect("funding TX must contain the expected output script") + as u16; + let final_channel_id = ChannelId::v1_from_funding_txid( + bitcoin::hashes::Hash::as_byte_array(&funding_txid), + funding_output_index, + ); + let pending_funding_path = static_state + .ldk_data_dir + .join(format!("pending_funding_{}", final_channel_id.0.as_hex())); + fs::write(&pending_funding_path, &funding_txid_str).unwrap(); let psbt_path = static_state .ldk_data_dir - .join(format!("psbt_{funding_txid}")); + .join(format!("psbt_{funding_txid_str}")); fs::write(psbt_path, psbt.to_string()).unwrap(); if let Some(asset_id) = asset_id { let unlocked_state_copy = unlocked_state.clone(); - let witness_id = funding_txid.clone(); + let witness_id = funding_txid_str.clone(); tokio::task::spawn_blocking(move || { unlocked_state_copy .rgb_upsert_witness( @@ -673,7 +838,7 @@ async fn handle_ldk_events( .unwrap(); let consignment_path = - unlocked_state.rgb_get_send_consignment_path(&asset_id, &funding_txid); + unlocked_state.rgb_get_send_consignment_path(&asset_id, &funding_txid_str); let proxy_url = TransportEndpoint::new(unlocked_state.proxy_endpoint.clone()) .unwrap() .endpoint; @@ -681,9 +846,9 @@ async fn handle_ldk_events( let res = tokio::task::spawn_blocking(move || { unlocked_state_copy.rgb_post_consignment( &proxy_url, - funding_txid.clone(), + funding_txid_str.clone(), &consignment_path, - funding_txid, + funding_txid_str, None, ) }) @@ -709,7 +874,8 @@ async fn handle_ldk_events( { tracing::error!( "ERROR: Channel went away before we could fund it. The peer disconnected or refused the channel."); - *unlocked_state.rgb_send_lock.lock().unwrap() = false; + handle_open_chan_fail(&final_channel_id, &static_state, unlocked_state.clone()) + .await; } } Event::FundingTxBroadcastSafe { .. } => { @@ -801,7 +967,7 @@ async fn handle_ldk_events( } } - _update_rgb_channel_amount(&static_state.ldk_data_dir, &payment_hash, true); + find_and_update_rgb_chan_amt(&static_state.ldk_data_dir, &payment_hash, true); if is_maker_swap { unlocked_state.update_maker_swap_status(&payment_hash, SwapStatus::Succeeded); } else { @@ -822,7 +988,7 @@ async fn handle_ldk_events( payment_id, .. } => { - _update_rgb_channel_amount(&static_state.ldk_data_dir, &payment_hash, false); + find_and_update_rgb_chan_amt(&static_state.ldk_data_dir, &payment_hash, false); if unlocked_state.is_maker_swap(&payment_hash) { tracing::info!( @@ -856,6 +1022,20 @@ async fn handle_ldk_events( ref counterparty_node_id, .. } => { + #[cfg(test)] + if IGNORE_INBOUND_CHANNELS_ON_NODE + .lock() + .unwrap() + .as_ref() + .is_some_and(|id| *id == unlocked_state.channel_manager.get_our_node_id()) + { + tracing::info!( + "TEST: ignoring inbound channel {} from {}", + temporary_channel_id, + hex_str(&counterparty_node_id.serialize()), + ); + return Ok(()); + } let mut random_bytes = [0u8; 16]; random_bytes .copy_from_slice(&unlocked_state.keys_manager.get_secure_random_bytes()[..16]); @@ -1088,7 +1268,10 @@ async fn handle_ldk_events( ReplayEvent() })?; - *unlocked_state.rgb_send_lock.lock().unwrap() = false; + let pending_funding_path = static_state + .ldk_data_dir + .join(format!("pending_funding_{}", channel_id.0.as_hex())); + fs::remove_file(&pending_funding_path).unwrap(); } else { // acceptor let consignment_path = static_state @@ -1146,19 +1329,20 @@ async fn handle_ldk_events( reason ); - *unlocked_state.rgb_send_lock.lock().unwrap() = false; - - unlocked_state.delete_channel_id(channel_id); + // the ChannelClosed event gets fired also after node crashes/restarts, so it's better + // to handle the failure here (regardless what the DiscardFunding event documents) + handle_open_chan_fail(&channel_id, &static_state, unlocked_state.clone()).await; } Event::DiscardFunding { channel_id, .. } => { - // A "real" node should probably "lock" the UTXOs spent in funding transactions until - // the funding transaction either confirms, or this event is generated. tracing::info!( "EVENT: Discarded funding for channel with ID {}", channel_id ); - unlocked_state.delete_channel_id(channel_id); + // this will probably do nothing, since the ChannelClosed event will be triggered + // before, but in case of splicing this should be the correct place to handle the + // failure + handle_open_chan_fail(&channel_id, &static_state, unlocked_state.clone()).await; } Event::HTLCIntercepted { is_swap, @@ -1792,11 +1976,12 @@ pub(crate) async fn start_ldk( }; // Prepare the RGB wallet + let witness_version = WitnessVersion::Taproot; let mnemonic_str = mnemonic.to_string(); let (_, account_xpub_vanilla, _) = - get_account_data(&bitcoin_network, &mnemonic_str, false).unwrap(); + get_account_data(&bitcoin_network, &mnemonic_str, false, witness_version).unwrap(); let (_, account_xpub_colored, master_fingerprint) = - get_account_data(&bitcoin_network, &mnemonic_str, true).unwrap(); + get_account_data(&bitcoin_network, &mnemonic_str, true, witness_version).unwrap(); let data_dir = static_state .storage_dir_path .clone() @@ -1808,6 +1993,7 @@ pub(crate) async fn start_ldk( vanilla_keychain: None, master_fingerprint: master_fingerprint.to_string(), mnemonic: Some(mnemonic.to_string()), + witness_version, }; let mut rgb_wallet = tokio::task::spawn_blocking(move || { RgbLibWallet::new( @@ -2140,7 +2326,6 @@ pub(crate) async fn start_ldk( taker_swaps, router: Arc::clone(&router), output_sweeper: Arc::clone(&output_sweeper), - rgb_send_lock: Arc::new(Mutex::new(false)), channel_ids_map, proxy_endpoint: proxy_endpoint.to_string(), }); diff --git a/src/rgb.rs b/src/rgb.rs index 002d9179..cda909ad 100644 --- a/src/rgb.rs +++ b/src/rgb.rs @@ -33,6 +33,10 @@ use std::sync::{Arc, Mutex, MutexGuard}; use crate::{error::APIError, utils::UnlockedAppState}; impl UnlockedAppState { + pub(crate) fn rgb_abort_pending_vanilla_tx(&self, txid: String) -> Result<(), RgbLibError> { + self.rgb_wallet_wrapper.abort_pending_vanilla_tx(txid) + } + pub(crate) fn rgb_blind_receive( &self, asset_id: Option, @@ -309,9 +313,10 @@ impl UnlockedAppState { address: String, amount: u64, fee_rate: u64, + dry_run: bool, ) -> Result { self.rgb_wallet_wrapper - .send_btc_begin(address, amount, fee_rate) + .send_btc_begin(address, amount, fee_rate, dry_run) } pub(crate) fn rgb_send_btc_end(&self, signed_psbt: String) -> Result { @@ -371,6 +376,10 @@ impl RgbLibWalletWrapper { self.wallet.lock().unwrap() } + pub(crate) fn abort_pending_vanilla_tx(&self, txid: String) -> Result<(), RgbLibError> { + self.get_rgb_wallet().abort_pending_vanilla_tx(txid) + } + pub(crate) fn bitcoin_network(&self) -> BitcoinNetwork { self.get_rgb_wallet().get_wallet_data().bitcoin_network } @@ -682,9 +691,10 @@ impl RgbLibWalletWrapper { address: String, amount: u64, fee_rate: u64, + dry_run: bool, ) -> Result { self.get_rgb_wallet() - .send_btc_begin(self.online, address, amount, fee_rate, false) + .send_btc_begin(self.online, address, amount, fee_rate, false, dry_run) } pub(crate) fn send_btc_end(&self, signed_psbt: String) -> Result { diff --git a/src/routes.rs b/src/routes.rs index e614385b..cf5d069f 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,4 +1,4 @@ -use amplify::{map, s, Display}; +use amplify::{s, Display}; use axum::{ extract::{Multipart, State}, Json, @@ -8,14 +8,14 @@ use biscuit_auth::Biscuit; use bitcoin::hashes::sha256::{self, Hash as Sha256}; use bitcoin::hashes::Hash; use bitcoin::secp256k1::PublicKey; -use bitcoin::{Network, ScriptBuf}; +use bitcoin::Network; use hex::DisplayHex; use lightning::ln::{channelmanager::OptionalOfferPaymentParams, types::ChannelId}; use lightning::offers::offer::{self, Offer}; use lightning::onion_message::messenger::Destination; use lightning::rgb_utils::{ get_rgb_channel_info_path, get_rgb_payment_info_path, parse_rgb_channel_info, - parse_rgb_payment_info, STATIC_BLINDING, + parse_rgb_payment_info, }; use lightning::routing::gossip::RoutingFees; use lightning::routing::router::{Path as LnPath, Route, RouteHint, RouteHintHop}; @@ -44,8 +44,7 @@ use lightning_invoice::{Bolt11Invoice, PaymentSecret}; use regex::Regex; use rgb_lib::{ bdk_wallet::keys::bip39::Mnemonic, - keys::generate_keys, - utils::recipient_id_from_script_buf, + keys::{generate_keys, WitnessVersion}, wallet::{ rust_only::{ check_indexer_url as rgb_lib_check_indexer_url, @@ -89,7 +88,7 @@ use crate::{ use crate::{ disk::{self, CHANNEL_PEER_DATA}, error::APIError, - ldk::{PaymentInfo, FEE_RATE, UTXO_SIZE_SAT}, + ldk::{PaymentInfo, UTXO_SIZE_SAT}, utils::{ connect_peer_if_necessary, get_current_timestamp, no_cancel, parse_peer_info, AppState, }, @@ -913,7 +912,7 @@ pub(crate) struct OpenChannelRequest { pub(crate) temporary_channel_id: Option, } -#[derive(Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize)] pub(crate) struct OpenChannelResponse { pub(crate) temporary_channel_id: String, } @@ -1205,7 +1204,8 @@ pub(crate) enum TransactionType { RgbSend, Drain, CreateUtxos, - User, + SendBtc, + Incoming, } #[derive(Debug, Deserialize, Serialize)] @@ -1952,10 +1952,6 @@ pub(crate) async fn inflate( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let unlocked_state_copy = unlocked_state.clone(); let inflate_result = tokio::task::spawn_blocking(move || { unlocked_state_copy.rgb_inflate( @@ -1991,7 +1987,7 @@ pub(crate) async fn init( Some(mnemonic) => Mnemonic::from_str(&mnemonic) .map_err(|e| APIError::InvalidMnemonic(e.to_string()))? .to_string(), - None => generate_keys(state.static_state.network).mnemonic, + None => generate_keys(state.static_state.network, WitnessVersion::Taproot).mnemonic, }; encrypt_and_save_mnemonic(payload.password, mnemonic.clone(), &mnemonic_path)?; @@ -2035,10 +2031,6 @@ pub(crate) async fn issue_asset_cfa( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let file_path = payload.file_digest.map(|d: String| { unlocked_state .rgb_get_media_dir() @@ -2070,10 +2062,6 @@ pub(crate) async fn issue_asset_ifa( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let asset = unlocked_state.rgb_issue_asset_ifa( payload.ticker, payload.name, @@ -2098,10 +2086,6 @@ pub(crate) async fn issue_asset_nia( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let asset = unlocked_state.rgb_issue_asset_nia( payload.ticker, payload.name, @@ -2124,10 +2108,6 @@ pub(crate) async fn issue_asset_uda( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let rgb_media_dir = unlocked_state.rgb_get_media_dir(); let get_string_path = |d: String| { rgb_media_dir @@ -2574,7 +2554,8 @@ pub(crate) async fn list_transactions( rgb_lib::wallet::TransactionType::RgbSend => TransactionType::RgbSend, rgb_lib::wallet::TransactionType::Drain => TransactionType::Drain, rgb_lib::wallet::TransactionType::CreateUtxos => TransactionType::CreateUtxos, - rgb_lib::wallet::TransactionType::User => TransactionType::User, + rgb_lib::wallet::TransactionType::SendBtc => TransactionType::SendBtc, + rgb_lib::wallet::TransactionType::Incoming => TransactionType::Incoming, }, txid: tx.txid, received: tx.received, @@ -3133,10 +3114,6 @@ pub(crate) async fn open_channel( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let temporary_channel_id = if let Some(tmp_chan_id_str) = payload.temporary_channel_id { let tmp_chan_id = check_channel_id(&tmp_chan_id_str)?; if unlocked_state.channel_ids().contains_key(&tmp_chan_id) { @@ -3261,67 +3238,29 @@ pub(crate) async fn open_channel( ..Default::default() }; - let consignment_endpoint = if let Some((contract_id, asset_amount)) = &colored_info { + // checks on balances here are not precise since they do not take fees into account + let (consignment_endpoint, schema) = if let Some((contract_id, asset_amount)) = &colored_info { + let balance = unlocked_state.rgb_get_btc_balance(true)?; + if payload.capacity_sat > balance.colored.spendable { + return Err(APIError::InsufficientFunds(payload.capacity_sat - balance.colored.spendable)); + } let balance = unlocked_state.rgb_get_asset_balance(*contract_id)?; - let spendable_rgb_amount = balance.spendable; - - if *asset_amount > spendable_rgb_amount { + if *asset_amount > balance.spendable { return Err(APIError::InsufficientAssets); } - - Some(RgbTransport::from_str(&unlocked_state.proxy_endpoint).unwrap()) - } else { - None - }; - - let schema = if let Some((contract_id, asset_amount)) = &colored_info { - let mut fake_p2wsh: [u8; 34] = [0; 34]; - fake_p2wsh[1] = 32; - let script_buf = ScriptBuf::from_bytes(fake_p2wsh.to_vec()); - let recipient_id = recipient_id_from_script_buf(script_buf, state.static_state.network); - let asset_id = contract_id.to_string(); + let consignment_endpoint = RgbTransport::from_str(&unlocked_state.proxy_endpoint).unwrap(); let schema = unlocked_state .rgb_get_asset_metadata(*contract_id)? .asset_schema; - let assignment = match schema { - RgbLibAssetSchema::Nia | RgbLibAssetSchema::Cfa | RgbLibAssetSchema::Ifa => { - Assignment::Fungible(*asset_amount) - } - RgbLibAssetSchema::Uda => Assignment::NonFungible, - }; - - let recipient_map = map! { - asset_id => vec![RgbLibRecipient { - recipient_id, - witness_data: Some(RgbLibWitnessData { - amount_sat: payload.capacity_sat, - blinding: Some(STATIC_BLINDING + 1), - }), - assignment: assignment.into(), - transport_endpoints: vec![unlocked_state.proxy_endpoint.clone()] - }]}; - - let unlocked_state_copy = unlocked_state.clone(); - tokio::task::spawn_blocking(move || { - unlocked_state_copy.rgb_send_begin( - recipient_map, - true, - FEE_RATE, - MIN_CHANNEL_CONFIRMATIONS, - None, - true, - ) - }) - .await - .unwrap()?; - Some(schema) + (Some(consignment_endpoint), Some(schema)) } else { - None + let balance = unlocked_state.rgb_get_btc_balance(true)?; + if payload.capacity_sat > balance.vanilla.spendable { + return Err(APIError::InsufficientFunds(payload.capacity_sat - balance.vanilla.spendable)); + } + (None, None) }; - *unlocked_state.rgb_send_lock.lock().unwrap() = true; - tracing::debug!("RGB send lock set to true"); - let temporary_channel_id = unlocked_state .channel_manager .create_channel( @@ -3335,8 +3274,7 @@ pub(crate) async fn open_channel( payload.push_asset_amount, ) .map_err(|e| { - *unlocked_state.rgb_send_lock.lock().unwrap() = false; - tracing::debug!("RGB send lock set to false (open channel failure: {e:?})"); + tracing::error!("Open channel failure: {e:?}"); match e { LDKAPIError::APIMisuseError { err } if err.contains("fee for initial commitment transaction") => @@ -3365,6 +3303,7 @@ pub(crate) async fn open_channel( schema: schema.unwrap(), local_rgb_amount: *asset_amount - push_amount, remote_rgb_amount: push_amount, + batch_transfer_idx: None, }; write_rgb_channel_info( &get_rgb_channel_info_path( @@ -3506,10 +3445,6 @@ pub(crate) async fn rgb_invoice( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let assignment = payload.assignment.unwrap_or(Assignment::Any).into(); let receive_data = if payload.witness { @@ -3819,10 +3754,6 @@ pub(crate) async fn send_rgb( let guard = state.check_unlocked().await?; let unlocked_state = guard.as_ref().unwrap(); - if *unlocked_state.rgb_send_lock.lock().unwrap() { - return Err(APIError::OpenChannelInProgress); - } - let recipient_map: HashMap> = payload .recipient_map .into_iter() diff --git a/src/test/authentication.rs b/src/test/authentication.rs index 97564b2a..b914182c 100644 --- a/src/test/authentication.rs +++ b/src/test/authentication.rs @@ -69,7 +69,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -90,7 +90,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -101,7 +101,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -152,7 +152,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -173,7 +173,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -188,7 +188,7 @@ async fn authentication() { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await diff --git a/src/test/drop_funding_signed.rs b/src/test/drop_funding_signed.rs new file mode 100644 index 00000000..1cd44f39 --- /dev/null +++ b/src/test/drop_funding_signed.rs @@ -0,0 +1,124 @@ +use super::*; + +const TEST_DIR_BASE: &str = "tmp/drop_funding_signed/"; + +#[serial_test::serial] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[traced_test] +async fn drop_funding_signed() { + initialize(); + + let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); + let test_dir_node2 = format!("{TEST_DIR_BASE}node2"); + let test_dir_node3 = format!("{TEST_DIR_BASE}node3"); + let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; + let (node2_addr, _) = start_node(&test_dir_node2, NODE2_PEER_PORT, false).await; + let (node3_addr, _) = start_node(&test_dir_node3, NODE3_PEER_PORT, false).await; + + // node1 only has enough funds for one vanilla channel; if the UTXOs stay locked, the second + // channel open will fail + fund_with_and_create_utxos(node1_addr, Some(1), 200_000).await; + fund_and_create_utxos(node2_addr, None).await; + fund_and_create_utxos(node3_addr, None).await; + + let node2_pubkey = node_info(node2_addr).await.pubkey; + let node3_pubkey = node_info(node3_addr).await.pubkey; + + // make node1 drop outgoing funding_signed and reply with an error + *DROP_FUNDING_SIGNED_ON_NODE.lock().unwrap() = + Some(PublicKey::from_str(&node2_pubkey).unwrap()); + + open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + Some(150_000), + None, + None, + None, + None, + None, + None, + None, + true, + ) + .await + .unwrap(); + + // wait for channel to disappear + let t_0 = OffsetDateTime::now_utc(); + loop { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let channels = list_channels(node1_addr).await; + if channels.is_empty() { + break; + } + if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 10.0 { + panic!("channel is not disappearing"); + } + } + + // restore normal behavior before opening a new channel to a different peer + *DROP_FUNDING_SIGNED_ON_NODE.lock().unwrap() = None; + + // opening a new channel to a different peer must succeed: the UTXOs locked for the discarded + // funding TX must have been released + open_channel_with_retry( + node1_addr, + &node3_pubkey, + Some(NODE3_PEER_PORT), + Some(100_000), + None, + None, + None, + None, + 30, + ) + .await; + + // do the same but with a colored channel + fund_with_and_create_utxos(node1_addr, Some(3), 500_000).await; + let asset_cfa = issue_asset_cfa(node1_addr, None).await; + *DROP_FUNDING_SIGNED_ON_NODE.lock().unwrap() = + Some(PublicKey::from_str(&node2_pubkey).unwrap()); + open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + Some(100_000), + None, + Some(ISSUE_AMT), + Some(&asset_cfa.asset_id), + None, + None, + None, + None, + true, + ) + .await + .unwrap(); + let t_0 = OffsetDateTime::now_utc(); + loop { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let channels = list_channels(node1_addr).await; + if channels.len() == 1 { + break; + } + if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 10.0 { + panic!("channel is not disappearing"); + } + } + *DROP_FUNDING_SIGNED_ON_NODE.lock().unwrap() = None; + open_channel_with_retry( + node1_addr, + &node3_pubkey, + Some(NODE3_PEER_PORT), + Some(100_000), + None, + Some(ISSUE_AMT), + Some(&asset_cfa.asset_id), + None, + 30, + ) + .await; +} diff --git a/src/test/missing_acceptor.rs b/src/test/missing_acceptor.rs new file mode 100644 index 00000000..f89eb974 --- /dev/null +++ b/src/test/missing_acceptor.rs @@ -0,0 +1,83 @@ +use super::*; + +const TEST_DIR_BASE: &str = "tmp/missing_acceptor/"; + +#[serial_test::serial] +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +#[traced_test] +async fn missing_acceptor() { + initialize(); + + let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); + let test_dir_node2 = format!("{TEST_DIR_BASE}node2"); + let test_dir_node3 = format!("{TEST_DIR_BASE}node3"); + let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; + let (node2_addr, _) = start_node(&test_dir_node2, NODE2_PEER_PORT, false).await; + let (node3_addr, _) = start_node(&test_dir_node3, NODE3_PEER_PORT, false).await; + + fund_and_create_utxos(node1_addr, None).await; + fund_and_create_utxos(node2_addr, None).await; + fund_and_create_utxos(node3_addr, None).await; + + let node2_info = node_info(node2_addr).await; + let node2_pubkey = node2_info.pubkey; + + let node3_info = node_info(node3_addr).await; + let node3_pubkey = node3_info.pubkey; + + *IGNORE_INBOUND_CHANNELS_ON_NODE.lock().unwrap() = + Some(PublicKey::from_str(&node2_pubkey).unwrap()); + + // opening a channel where the acceptor is missing should not lock the funds + let stuck_channel = open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + None, + None, + None, + None, + None, + None, + None, + None, + true, + ) + .await + .unwrap(); + let stuck_temp_id = stuck_channel.temporary_channel_id; + + // the stuck channel should be visible on node1 + let channels_before = list_channels(node1_addr).await; + assert!(channels_before + .iter() + .any(|c| c.channel_id == stuck_temp_id)); + + // make sure a new channel can be opened + open_channel_with_retry( + node1_addr, + &node3_pubkey, + Some(NODE3_PEER_PORT), + None, + None, + None, + None, + None, + 30, + ) + .await; + + *IGNORE_INBOUND_CHANNELS_ON_NODE.lock().unwrap() = None; + + assert_eq!(list_channels(node1_addr).await.len(), 2); + + // the stuck channel can be force-closed via the /closechannel API, + // this ensures the UTXOs can be unlocked in case of a missing acceptor + close_channel(node1_addr, &stuck_temp_id, &node2_pubkey, true).await; + + // after closing, only the channel to node3 should remain on node1 + let channels_after = list_channels(node1_addr).await; + assert!(!channels_after.iter().any(|c| c.channel_id == stuck_temp_id)); + assert_eq!(channels_after.len(), 1); + assert_eq!(channels_after[0].peer_pubkey, node3_pubkey); +} diff --git a/src/test/mod.rs b/src/test/mod.rs index 0db01e5b..e2c99e3d 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -2,9 +2,13 @@ use amplify::s; use biscuit_auth::{builder::date, macros::*, KeyPair}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; +use bitcoin::secp256k1::PublicKey; +use bitcoin::{Amount, Denomination}; use chrono::{DateTime, Local, Utc}; use electrum_client::ElectrumApi; +use http::response::Builder; use lazy_static::lazy_static; +use lightning::ln::channelmanager::DROP_FUNDING_SIGNED_ON_NODE; use lightning_invoice::Bolt11Invoice; use once_cell::sync::Lazy; use reqwest::Response; @@ -24,7 +28,7 @@ use tracing_test::traced_test; use crate::disk::LDK_LOGS_FILE; use crate::error::APIErrorResponse; -use crate::ldk::FEE_RATE; +use crate::ldk::{FEE_RATE, IGNORE_INBOUND_CHANNELS_ON_NODE}; use crate::routes::{ AddressResponse, AssetBalanceRequest, AssetBalanceResponse, AssetCFA, AssetIFA, AssetNIA, AssetUDA, Assignment, BackupRequest, BtcBalanceRequest, BtcBalanceResponse, @@ -59,6 +63,8 @@ const NODE4_PEER_PORT: u16 = 9804; const NODE5_PEER_PORT: u16 = 9805; const NODE6_PEER_PORT: u16 = 9806; +const ISSUE_AMT: u64 = 1000; + const DURATION_SECONDS: u64 = 999; static INIT: Once = Once::new(); @@ -111,7 +117,7 @@ impl Drop for ElectrsRestartGuard { } } -fn _bitcoin_cli() -> [String; 7] { +fn bitcoin_cli() -> [String; 7] { [ s!("exec"), s!("-T"), @@ -130,7 +136,7 @@ fn check_preimage_matches_hash(payment: &Payment, expected_payment_hash: &str) { assert_eq!(payment_preimage_hash, expected_payment_hash); } -async fn _check_response_is_ok(res: Response) -> Response { +async fn check_response_is_ok(res: Response) -> Response { if res.status() != reqwest::StatusCode::OK { panic!("reqwest response is not OK: {:?}", res.text().await); } @@ -150,28 +156,30 @@ async fn check_response_is_nok( assert_eq!(api_error_response.name, expected_name); } -fn _fund_wallet(address: String) { +fn fund_wallet(address: String, sats: u64) { + let amt = Amount::from_sat(sats); + let btc_str = amt.to_string_in(Denomination::Bitcoin); let status = Command::new("docker") .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) .arg("compose") - .args(_bitcoin_cli()) + .args(bitcoin_cli()) .arg("-rpcwallet=miner") .arg("sendtoaddress") .arg(address) - .arg("1") + .arg(btc_str) .status() .expect("failed to fund wallet"); assert!(status.success()); } -fn _get_txout(txid: &str) -> String { +fn get_txout(txid: &str) -> String { String::from_utf8( Command::new("docker") .stdin(Stdio::null()) .arg("compose") - .args(_bitcoin_cli()) + .args(bitcoin_cli()) .arg("-rpcwallet=miner") .arg("gettxout") .arg(txid) @@ -213,7 +221,7 @@ async fn start_daemon( async fn init(node_address: SocketAddr, password: &str, mnemonic: Option) -> InitResponse { let res = init_res(node_address, password, mnemonic).await; - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -250,7 +258,7 @@ async fn init_with_bearer( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -284,7 +292,7 @@ async fn address(node_address: SocketAddr) -> String { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -303,7 +311,7 @@ async fn asset_balance(node_address: SocketAddr, asset_id: &str) -> AssetBalance .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -332,7 +340,7 @@ async fn backup(node_address: SocketAddr, backup_path: &str, password: &str) { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -348,7 +356,7 @@ async fn btc_balance(node_address: SocketAddr) -> BtcBalanceResponse { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -367,7 +375,7 @@ async fn change_password(node_address: SocketAddr, old_password: &str, new_passw .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -407,7 +415,7 @@ async fn close_channel(node_address: SocketAddr, channel_id: &str, peer_pubkey: .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -442,7 +450,7 @@ async fn connect_peer(node_address: SocketAddr, peer_pubkey: &str, peer_addr: &s .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -479,7 +487,7 @@ async fn create_utxos(node_address: SocketAddr, up_to: bool, num: Option, si .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -497,7 +505,7 @@ async fn decode_ln_invoice(node_address: SocketAddr, invoice: &str) -> DecodeLNI .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -515,7 +523,7 @@ async fn decode_rgb_invoice(node_address: SocketAddr, invoice: &str) -> DecodeRG .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -533,7 +541,7 @@ async fn disconnect_peer(node_address: SocketAddr, peer_pubkey: &str) { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -555,7 +563,7 @@ async fn fail_transfers(node_address: SocketAddr, batch_transfer_idx: Option() .await @@ -563,17 +571,21 @@ async fn fail_transfers(node_address: SocketAddr, batch_transfer_idx: Option) { +async fn fund_with_and_create_utxos(node_address: SocketAddr, num: Option, sats: u64) { println!("funding wallet for node {node_address}"); let addr = address(node_address).await; - _fund_wallet(addr); + fund_wallet(addr, sats); mine(false); create_utxos(node_address, false, Some(num.unwrap_or(10)), None).await; mine(false); } +async fn fund_and_create_utxos(node_address: SocketAddr, num: Option) { + fund_with_and_create_utxos(node_address, num, 100_000_000).await; +} + async fn get_asset_media(node_address: SocketAddr, digest: &str) -> String { println!("requesting media for digest {digest} from node {node_address}"); let payload = GetAssetMediaRequest { @@ -585,7 +597,7 @@ async fn get_asset_media(node_address: SocketAddr, digest: &str) -> String { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -604,7 +616,7 @@ async fn get_channel_id(node_address: SocketAddr, temp_chan_id: &str) -> String .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -626,7 +638,7 @@ async fn inflate(node_address: SocketAddr, asset_id: &str, inflation_amount: u64 .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -644,7 +656,7 @@ async fn invoice_status(node_address: SocketAddr, invoice: &str) -> InvoiceStatu .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -671,7 +683,7 @@ async fn issue_asset_cfa(node_address: SocketAddr, file_path: Option<&str>) -> A .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -682,7 +694,7 @@ async fn issue_asset_cfa(node_address: SocketAddr, file_path: Option<&str>) -> A async fn issue_asset_ifa(node_address: SocketAddr) -> AssetIFA { println!("issuing IFA asset on node {node_address}"); let payload = IssueAssetIFARequest { - amounts: vec![1000], + amounts: vec![ISSUE_AMT], inflation_amounts: vec![2000], ticker: s!("USDT"), name: s!("Tether"), @@ -695,7 +707,7 @@ async fn issue_asset_ifa(node_address: SocketAddr) -> AssetIFA { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -706,7 +718,7 @@ async fn issue_asset_ifa(node_address: SocketAddr) -> AssetIFA { async fn issue_asset_nia(node_address: SocketAddr) -> AssetNIA { println!("issuing NIA asset on node {node_address}"); let payload = IssueAssetNIARequest { - amounts: vec![1000], + amounts: vec![ISSUE_AMT], ticker: s!("USDT"), name: s!("Tether"), precision: 0, @@ -717,7 +729,7 @@ async fn issue_asset_nia(node_address: SocketAddr) -> AssetNIA { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -745,7 +757,7 @@ async fn issue_asset_uda(node_address: SocketAddr, file_path: Option<&str>) -> A .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -753,7 +765,7 @@ async fn issue_asset_uda(node_address: SocketAddr, file_path: Option<&str>) -> A .asset } -async fn _with_ln_balance_checks( +async fn with_ln_balance_checks( node_address: SocketAddr, counterparty_node_address: SocketAddr, asset_id: Option, @@ -789,7 +801,7 @@ async fn _with_ln_balance_checks( .await; } -async fn _keysend_raw( +async fn keysend_raw( node_address: SocketAddr, dest_pubkey: &str, amt_msat: Option, @@ -813,7 +825,7 @@ async fn _keysend_raw( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -827,7 +839,7 @@ async fn keysend( asset_id: Option<&str>, asset_amount: Option, ) -> Payment { - let keysend = _keysend_raw(node_address, dest_pubkey, amt_msat, asset_id, asset_amount).await; + let keysend = keysend_raw(node_address, dest_pubkey, amt_msat, asset_id, asset_amount).await; wait_for_ln_payment(node_address, &keysend.payment_hash, HTLCStatus::Succeeded).await } @@ -842,9 +854,9 @@ async fn keysend_with_ln_balance( initial_ln_balance_rgb: Option, counterparty_initial_ln_balance_rgb: Option, ) { - let res = _keysend_raw(node_address, dest_pubkey, amt_msat, asset_id, asset_amount).await; + let res = keysend_raw(node_address, dest_pubkey, amt_msat, asset_id, asset_amount).await; - _with_ln_balance_checks( + with_ln_balance_checks( node_address, counterparty_node_address, asset_id.map(|a| a.to_string()), @@ -867,7 +879,7 @@ async fn list_assets(node_address: SocketAddr) -> ListAssetsResponse { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -881,7 +893,7 @@ async fn list_channels(node_address: SocketAddr) -> Vec { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -896,7 +908,7 @@ async fn list_payments(node_address: SocketAddr) -> Vec { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -914,7 +926,7 @@ async fn get_payment(node_address: SocketAddr, payment_hash: &str) -> Payment { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -929,7 +941,7 @@ async fn list_peers(node_address: SocketAddr) -> Vec { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -944,7 +956,7 @@ async fn list_swaps(node_address: SocketAddr) -> ListSwapsResponse { .send() .await .unwrap(); - _check_response_is_ok(res).await.json().await.unwrap() + check_response_is_ok(res).await.json().await.unwrap() } async fn get_swap(node_address: SocketAddr, payment_hash: &str, taker: bool) -> Swap { @@ -959,7 +971,7 @@ async fn get_swap(node_address: SocketAddr, payment_hash: &str, taker: bool) -> .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -976,7 +988,7 @@ async fn list_transactions(node_address: SocketAddr) -> Vec { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -995,7 +1007,7 @@ async fn list_transfers(node_address: SocketAddr, asset_id: &str) -> Vec() .await @@ -1012,7 +1024,7 @@ async fn list_unspents(node_address: SocketAddr) -> Vec { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1042,7 +1054,7 @@ async fn ln_invoice( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1056,7 +1068,7 @@ async fn lock(node_address: SocketAddr) { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1070,7 +1082,7 @@ async fn maker_execute( taker_pubkey: String, ) { let res = maker_execute_raw(node_address, swapstring, payment_secret, taker_pubkey).await; - let _ = _check_response_is_ok(res) + let _ = check_response_is_ok(res) .await .json::() .await; @@ -1121,7 +1133,7 @@ async fn maker_init( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1135,7 +1147,7 @@ async fn network_info(node_address: SocketAddr) -> NetworkInfoResponse { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1149,7 +1161,7 @@ async fn node_info(node_address: SocketAddr) -> NodeInfoResponse { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1215,17 +1227,18 @@ async fn open_channel_with_retry( match result { Ok(channel) => return channel, - Err(status) if status == reqwest::StatusCode::FORBIDDEN && attempt < max_retries => { + Err(res) if res.status() == reqwest::StatusCode::FORBIDDEN && attempt < max_retries => { println!( "Channel opening in progress (attempt {}/{}), retrying in 5s...", attempt, max_retries ); tokio::time::sleep(std::time::Duration::from_secs(5)).await; } - Err(status) => { + Err(res) => { panic!( "Failed to open channel after {} attempts with status: {}", - attempt, status + attempt, + res.status() ); } } @@ -1246,7 +1259,7 @@ async fn open_channel_funded_raw( fee_proportional_millionths: Option, temporary_channel_id: Option<&str>, with_anchors: bool, -) -> Result { +) -> Result { open_channel_raw( node_address, dest_peer_pubkey, @@ -1284,7 +1297,7 @@ async fn open_channel_funded_raw( && asset_amounts_match }) { if let Some(txid) = &channel.funding_txid { - let txout = _get_txout(txid); + let txout = get_txout(txid); if !txout.is_empty() { mine_n_blocks(false, 6); channel_id = Some(channel.channel_id.clone()); @@ -1294,7 +1307,16 @@ async fn open_channel_funded_raw( } } if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 50.0 { - panic!("cannot find funding TX") + // channel may have been force-closed before reaching ChannelPending + // (e.g. InsufficientAssignments in FundingGenerationReady). + // return an error so the retry logic can try again. + println!("cannot find funding TX for channel to {dest_peer_pubkey}"); + return Err(Response::from( + Builder::new() + .status(reqwest::StatusCode::FORBIDDEN) + .body("") + .unwrap(), + )); } } let channel_id = channel_id.unwrap(); @@ -1330,7 +1352,7 @@ async fn open_channel_raw( fee_proportional_millionths: Option, temporary_channel_id: Option<&str>, with_anchors: bool, -) -> Result { +) -> Result { println!( "opening channel with {asset_amount:?} of asset {asset_id:?} from node {node_address} \ to {dest_peer_pubkey}" @@ -1376,7 +1398,7 @@ async fn open_channel_raw( let status = res.status(); if !status.is_success() { - return Err(status); + return Err(res); } Ok(res.json::().await.unwrap()) @@ -1426,7 +1448,7 @@ async fn post_asset_media(node_address: SocketAddr, file_path: &str) -> String { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1443,7 +1465,7 @@ async fn refresh_transfers(node_address: SocketAddr) { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1462,7 +1484,7 @@ async fn restore(node_address: SocketAddr, backup_path: &str, password: &str) { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1506,7 +1528,7 @@ async fn rgb_invoice_with_assignment( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1560,7 +1582,7 @@ async fn send_assets( .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1581,7 +1603,7 @@ async fn send_btc(node_address: SocketAddr, amount: u64, address: &str) -> Strin .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1603,7 +1625,7 @@ async fn send_payment_raw(node_address: SocketAddr, invoice: String) -> SendPaym .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1625,7 +1647,7 @@ async fn send_payment_with_ln_balance( let res = send_payment_raw(node_address, invoice).await; - _with_ln_balance_checks( + with_ln_balance_checks( node_address, counterparty_node_address, bolt11_invoice.rgb_contract_id().map(|c| c.to_string()), @@ -1662,7 +1684,7 @@ async fn shutdown(node_sockets: &[SocketAddr]) { .send() .await .unwrap(); - _check_response_is_ok(res).await; + check_response_is_ok(res).await; } // check node sockets have been released let t_0 = OffsetDateTime::now_utc(); @@ -1694,7 +1716,7 @@ async fn taker(node_address: SocketAddr, swapstring: String) -> EmptyResponse { .send() .await .unwrap(); - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1729,7 +1751,7 @@ async fn unlock_res(node_address: SocketAddr, password: &str) -> Response { async fn unlock(node_address: SocketAddr, password: &str) { println!("unlocking node {node_address}"); let res = unlock_res(node_address, password).await; - _check_response_is_ok(res) + check_response_is_ok(res) .await .json::() .await @@ -1857,7 +1879,7 @@ impl Miner { .stdout(Stdio::null()) .stderr(Stdio::null()) .arg("compose") - .args(_bitcoin_cli()) + .args(bitcoin_cli()) .arg("-rpcwallet=miner") .arg("-generate") .arg(num_blocks.to_string()) @@ -1925,7 +1947,7 @@ fn get_block_count() -> u32 { .stdin(Stdio::null()) .stderr(Stdio::null()) .arg("compose") - .args(_bitcoin_cli()) + .args(bitcoin_cli()) .arg("getblockcount") .output() .expect("failed to call getblockcount"); @@ -2002,6 +2024,7 @@ mod close_force_other_side; mod close_force_standard; mod concurrent_btc_payments; mod concurrent_openchannel; +mod drop_funding_signed; mod fail_transfers; mod getchannelid; mod htlc_amount_checks; @@ -2010,6 +2033,7 @@ mod init; mod invoice; mod issue; mod lock_unlock_changepassword; +mod missing_acceptor; mod multi_hop; mod multi_open_close; mod open_after_double_send; diff --git a/src/test/openchannel_fail.rs b/src/test/openchannel_fail.rs index e8c78f0f..906793c4 100644 --- a/src/test/openchannel_fail.rs +++ b/src/test/openchannel_fail.rs @@ -1,11 +1,11 @@ use super::*; -const TEST_DIR_BASE: &str = "tmp/open_fail/"; +const TEST_DIR_BASE: &str = "tmp/openchannel_fail/"; #[serial_test::serial] #[tokio::test(flavor = "multi_thread", worker_threads = 1)] #[traced_test] -async fn open_fail() { +async fn openchannel_fail() { initialize(); let test_dir_node1 = format!("{TEST_DIR_BASE}node1"); @@ -13,40 +13,35 @@ async fn open_fail() { let (node1_addr, _) = start_node(&test_dir_node1, NODE1_PEER_PORT, false).await; let (node2_addr, _) = start_node(&test_dir_node2, NODE2_PEER_PORT, false).await; - fund_and_create_utxos(node1_addr, Some(1)).await; + fund_with_and_create_utxos(node1_addr, Some(1), 300_000).await; fund_and_create_utxos(node2_addr, None).await; let asset_id = issue_asset_nia(node1_addr).await.asset_id; let node2_info = node_info(node2_addr).await; - let node2_pubkey = node2_info.pubkey; - // open with insufficient allocation slots - let payload = OpenChannelRequest { - peer_pubkey_and_opt_addr: format!("{node2_pubkey}@127.0.0.1:{NODE2_PEER_PORT}"), - capacity_sat: 100_000, - push_msat: 3_500_000, - asset_amount: Some(100), - asset_id: Some(asset_id.clone()), - push_asset_amount: None, - public: true, - with_anchors: true, - fee_base_msat: None, - fee_proportional_millionths: None, - temporary_channel_id: None, - }; - let res = reqwest::Client::new() - .post(format!("http://{node1_addr}/openchannel")) - .json(&payload) - .send() - .await - .unwrap(); + // insufficient BTC funds + let res = open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + Some(300_000), + None, + None, + None, + None, + None, + None, + None, + true, + ) + .await; check_response_is_nok( - res, + res.unwrap_err(), reqwest::StatusCode::FORBIDDEN, - "No uncolored UTXOs are available (hint: call createutxos)", - "NoAvailableUtxos", + "Not enough funds", + "InsufficientFunds", ) .await; @@ -55,7 +50,65 @@ async fn open_fail() { assert_eq!(channels_1.len(), 0); assert_eq!(channels_2.len(), 0); + // insufficient colored bitcoin funds + fund_wallet(address(node2_addr).await, 1000000); + let res = open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + None, + None, + Some(200), + Some(&asset_id), + None, + None, + None, + None, + true, + ) + .await; + check_response_is_nok( + res.unwrap_err(), + reqwest::StatusCode::FORBIDDEN, + "Not enough funds", + "InsufficientFunds", + ) + .await; + + let channels_1 = list_channels(node1_addr).await; + let channels_2 = list_channels(node2_addr).await; + assert_eq!(channels_1.len(), 0); + assert_eq!(channels_2.len(), 0); + + // insufficient RGB assets fund_and_create_utxos(node1_addr, Some(9)).await; + let res = open_channel_raw( + node1_addr, + &node2_pubkey, + Some(NODE2_PEER_PORT), + None, + None, + Some(ISSUE_AMT + 1), + Some(&asset_id), + None, + None, + None, + None, + true, + ) + .await; + check_response_is_nok( + res.unwrap_err(), + reqwest::StatusCode::FORBIDDEN, + "Not enough assets", + "InsufficientAssets", + ) + .await; + + let channels_1 = list_channels(node1_addr).await; + let channels_2 = list_channels(node2_addr).await; + assert_eq!(channels_1.len(), 0); + assert_eq!(channels_2.len(), 0); // open with unknown asset let payload = OpenChannelRequest { @@ -85,6 +138,11 @@ async fn open_fail() { ) .await; + let channels_1 = list_channels(node1_addr).await; + let channels_2 = list_channels(node2_addr).await; + assert_eq!(channels_1.len(), 0); + assert_eq!(channels_2.len(), 0); + // open with bad asset amount let payload = OpenChannelRequest { peer_pubkey_and_opt_addr: format!("{node2_pubkey}@127.0.0.1:{NODE2_PEER_PORT}"), @@ -479,70 +537,4 @@ async fn open_fail() { let channels_2 = list_channels(node2_addr).await; assert_eq!(channels_1.len(), 0); assert_eq!(channels_2.len(), 0); - - // open a 1st channel (success) - let payload = OpenChannelRequest { - peer_pubkey_and_opt_addr: format!("{node2_pubkey}@127.0.0.1:{NODE2_PEER_PORT}"), - capacity_sat: 100_000, - push_msat: 3_500_000, - asset_amount: Some(100), - asset_id: Some(asset_id.clone()), - push_asset_amount: None, - public: true, - with_anchors: true, - fee_base_msat: None, - fee_proportional_millionths: None, - temporary_channel_id: None, - }; - let res = reqwest::Client::new() - .post(format!("http://{node1_addr}/openchannel")) - .json(&payload) - .send() - .await - .unwrap(); - assert!(res.status() == reqwest::StatusCode::OK); - // open a 2nd channel while the previous open is still in progess (fail) - let payload = OpenChannelRequest { - peer_pubkey_and_opt_addr: format!("{node2_pubkey}@127.0.0.1:{NODE2_PEER_PORT}"), - capacity_sat: 100_000, - push_msat: 3_500_000, - asset_amount: Some(100), - asset_id: Some(asset_id), - push_asset_amount: None, - public: true, - with_anchors: true, - fee_base_msat: None, - fee_proportional_millionths: None, - temporary_channel_id: None, - }; - let res = reqwest::Client::new() - .post(format!("http://{node1_addr}/openchannel")) - .json(&payload) - .send() - .await - .unwrap(); - check_response_is_nok( - res, - reqwest::StatusCode::FORBIDDEN, - "Cannot perform this operation while an open channel operation is in progress", - "OpenChannelInProgress", - ) - .await; - - let t_0 = OffsetDateTime::now_utc(); - loop { - let channels_1 = list_channels(node1_addr).await; - let channels_2 = list_channels(node2_addr).await; - if channels_1.len() == 1 && channels_2.len() == 1 { - break; - } - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 10.0 { - panic!( - "expected one pending channel on both nodes, got {} and {}", - channels_1.len(), - channels_2.len() - ); - } - } } diff --git a/src/test/payment.rs b/src/test/payment.rs index 402d977c..49526d2a 100644 --- a/src/test/payment.rs +++ b/src/test/payment.rs @@ -191,7 +191,7 @@ async fn success() { .unwrap(); let tx_utxos = transactions.iter().find(|t| t.sent == 100000000).unwrap(); let tx_send = transactions.iter().find(|t| t.sent == 128000).unwrap(); - assert_eq!(tx_user.transaction_type, TransactionType::User); + assert_eq!(tx_user.transaction_type, TransactionType::Incoming); assert_eq!(tx_utxos.transaction_type, TransactionType::CreateUtxos); assert_eq!(tx_send.transaction_type, TransactionType::RgbSend); assert!(tx_utxos.confirmation_time.is_some()); diff --git a/src/utils.rs b/src/utils.rs index c214f086..27aa3372 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -108,7 +108,6 @@ pub(crate) struct UnlockedAppState { pub(crate) rgb_wallet_wrapper: Arc, pub(crate) router: Arc, pub(crate) output_sweeper: Arc, - pub(crate) rgb_send_lock: Arc>, pub(crate) channel_ids_map: Arc>, pub(crate) proxy_endpoint: String, }