From 481a8280fcf0d9248f2a80f286007c7dc3f27b3c Mon Sep 17 00:00:00 2001 From: benthecarman Date: Thu, 18 Jan 2024 18:18:07 +0000 Subject: [PATCH 1/2] Update ldk 121, bdk alpha5, bitcoin 0.30 --- Cargo.lock | 839 +++++++++++++++++++-------------- Cargo.toml | 10 +- mutiny-core/Cargo.toml | 26 +- mutiny-core/src/error.rs | 102 ++-- mutiny-core/src/event.rs | 41 +- mutiny-core/src/federation.rs | 91 ++-- mutiny-core/src/fees.rs | 21 +- mutiny-core/src/gossip.rs | 11 +- mutiny-core/src/key.rs | 2 +- mutiny-core/src/keymanager.rs | 27 +- mutiny-core/src/labels.rs | 57 ++- mutiny-core/src/ldkstorage.rs | 57 ++- mutiny-core/src/lib.rs | 69 +-- mutiny-core/src/lnurlauth.rs | 2 +- mutiny-core/src/logging.rs | 8 +- mutiny-core/src/lsp/lsps.rs | 51 +- mutiny-core/src/node.rs | 138 +++--- mutiny-core/src/nodemanager.rs | 126 ++--- mutiny-core/src/nostr/mod.rs | 12 +- mutiny-core/src/nostr/nwc.rs | 43 +- mutiny-core/src/onchain.rs | 276 ++++++----- mutiny-core/src/peermanager.rs | 20 +- mutiny-core/src/scorer.rs | 88 +++- mutiny-core/src/storage.rs | 31 +- mutiny-core/src/test_utils.rs | 3 +- mutiny-core/src/utils.rs | 26 + mutiny-core/src/vss.rs | 7 +- mutiny-wasm/Cargo.toml | 9 +- mutiny-wasm/src/error.rs | 15 +- mutiny-wasm/src/lib.rs | 26 +- mutiny-wasm/src/models.rs | 45 +- 31 files changed, 1267 insertions(+), 1012 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8db85684e..313e3b513 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,15 +84,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "aquamarine" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df752953c49ce90719c7bf1fc587bc8227aed04732ea0c0f85e5397d7fdbd1a1" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" dependencies = [ "include_dir", "itertools 0.10.5", @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "argon2" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ba4cac0a46bc1d2912652a751c47f2a9f3a7fe89bcae2275d418f5270402f9" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" dependencies = [ "base64ct", "blake2", @@ -131,11 +131,11 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7125e42787d53db9dd54261812ef17e937c95a51e4d291373b670342fa44310c" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "event-listener 4.0.2", + "event-listener 4.0.3", "event-listener-strategy", "pin-project-lite", ] @@ -148,7 +148,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -170,18 +170,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -260,9 +260,9 @@ checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64-compat" @@ -281,16 +281,15 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bdk" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c748f5f3167395cdad782428e9ccb496deca0ba2405f2aff49bda50ee3065fc0" +checksum = "21101f7c9d9fb1c3ece2da4e351c5885b4a72ae9a623fd0f6a0791e62fb12ea5" dependencies = [ "bdk_chain", - "bitcoin 0.29.2", + "bitcoin 0.30.2", "getrandom", "js-sys", - "log", - "miniscript", + "miniscript 10.0.0", "rand", "serde", "serde_json", @@ -309,24 +308,24 @@ dependencies = [ [[package]] name = "bdk_chain" -version = "0.5.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaba1449489201f5e6d4d3905b7e02aad6270b9215665c649c4a4dcee5bde4e0" +checksum = "cbde024deaffc2ad0cf4e88b0bd84409fe03a16e39f579aa7161cff79f491b71" dependencies = [ - "bitcoin 0.29.2", - "miniscript", + "bitcoin 0.30.2", + "miniscript 10.0.0", "serde", ] [[package]] name = "bdk_esplora" -version = "0.3.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ee3e68680372e8a44544426fa9fad7a817ce158ce06fb6127400c0c39b426b" +checksum = "a0208259118f26aaf6b598c8c6d89a2d03c6fa3dd97ebc29e4192e83e4ad4257" dependencies = [ "async-trait", "bdk_chain", - "esplora-client", + "esplora-client 0.6.0", "futures", ] @@ -360,7 +359,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9532c632b068e45a478f5e309126b6e2ec1dbf0bbd327b73836f33d9a43ede" dependencies = [ - "bitcoin 0.30.1", + "bitcoin 0.30.2", "percent-encoding-rfc3986", ] @@ -383,7 +382,6 @@ version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ - "base64 0.13.1", "bech32", "bitcoin_hashes 0.11.0", "core2", @@ -394,9 +392,9 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.30.1" +version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e99ff7289b20a7385f66a0feda78af2fc119d28fb56aea8886a9cd0a4abdd75" +checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ "base64 0.13.1", "bech32", @@ -407,6 +405,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitcoin-internals" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9997f8650dd818369931b5672a18dbef95324d0513aa99aae758de8ce86e5b" + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -465,9 +469,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -592,9 +596,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ "android-tzdata", "iana-time-zone", @@ -602,14 +606,14 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.52.0", ] [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -618,15 +622,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -663,9 +667,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -673,9 +677,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core2" @@ -688,21 +692,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crossbeam-utils" -version = "0.8.17" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -732,9 +733,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "difflib" @@ -809,12 +810,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -829,6 +830,19 @@ dependencies = [ "serde", ] +[[package]] +name = "esplora-client" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb1f7f2489cce83bc3bd92784f9ba5271eeb6e729b975895fc541f78cbfcdca" +dependencies = [ + "bitcoin 0.30.2", + "bitcoin-internals", + "log", + "reqwest", + "serde", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -837,9 +851,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.2" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "218a870470cce1469024e9fb66b901aa983929d81304a1cdb299f28118e550d5" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" dependencies = [ "concurrent-queue", "parking", @@ -852,7 +866,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" dependencies = [ - "event-listener 4.0.2", + "event-listener 4.0.3", "pin-project-lite", ] @@ -871,7 +885,7 @@ dependencies = [ "argon2", "hex", "rand", - "ring 0.17.5", + "ring 0.17.7", ] [[package]] @@ -895,7 +909,7 @@ dependencies = [ "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", "bitcoincore-rpc", - "esplora-client", + "esplora-client 0.5.0", "fedimint-core", "fedimint-logging", "lazy_static", @@ -932,7 +946,7 @@ dependencies = [ "futures", "itertools 0.10.5", "rand", - "ring 0.17.5", + "ring 0.17.7", "secp256k1-zkp", "serde", "serde_json", @@ -956,7 +970,7 @@ dependencies = [ "bech32", "bincode", "bitcoin 0.29.2", - "bitcoin 0.30.1", + "bitcoin 0.30.2", "bitcoin_hashes 0.11.0", "bitvec", "erased-serde", @@ -974,10 +988,10 @@ dependencies = [ "jsonrpsee-types", "jsonrpsee-wasm-client", "jsonrpsee-ws-client", - "lightning", - "lightning-invoice", + "lightning 0.0.118", + "lightning-invoice 0.26.0", "macro_rules_attribute", - "miniscript", + "miniscript 9.0.2", "parity-scale-codec", "rand", "secp256k1-zkp", @@ -1014,7 +1028,7 @@ dependencies = [ "fedimint-core", "fedimint-hkdf", "fedimint-tbs", - "ring 0.17.5", + "ring 0.17.7", "secp256k1-zkp", ] @@ -1045,7 +1059,7 @@ dependencies = [ "fedimint-threshold-crypto", "futures", "itertools 0.10.5", - "lightning-invoice", + "lightning-invoice 0.26.0", "rand", "reqwest", "secp256k1 0.24.3", @@ -1076,8 +1090,8 @@ dependencies = [ "fedimint-threshold-crypto", "futures", "itertools 0.10.5", - "lightning", - "lightning-invoice", + "lightning 0.0.118", + "lightning-invoice 0.26.0", "rand", "secp256k1 0.24.3", "serde", @@ -1212,7 +1226,7 @@ dependencies = [ "fedimint-wallet-common", "futures", "impl-tools", - "miniscript", + "miniscript 9.0.2", "rand", "secp256k1 0.24.3", "serde", @@ -1238,7 +1252,7 @@ dependencies = [ "fedimint-core", "futures", "impl-tools", - "miniscript", + "miniscript 9.0.2", "rand", "secp256k1 0.24.3", "serde", @@ -1293,9 +1307,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -1314,9 +1328,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1329,9 +1343,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1339,15 +1353,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1356,32 +1370,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" @@ -1395,9 +1409,9 @@ dependencies = [ [[package]] name = "futures-util" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1423,9 +1437,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -1446,9 +1460,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gloo-net" @@ -1509,9 +1523,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.21" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -1519,7 +1533,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap", "slab", "tokio", "tokio-util", @@ -1528,9 +1542,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "bc52e53916c08643f1b56ec082790d1e86a32e58dc5268f897f313fbae7b4872" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -1542,12 +1560,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.3" @@ -1562,9 +1574,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -1575,6 +1587,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex_fmt" version = "0.3.0" @@ -1598,9 +1616,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1609,9 +1627,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1632,9 +1650,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1647,7 +1665,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1663,7 +1681,7 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls 0.21.8", + "rustls 0.21.10", "tokio", "tokio-rustls 0.24.1", ] @@ -1683,9 +1701,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1714,6 +1732,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if_chain" version = "1.0.2" @@ -1776,19 +1804,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1842,15 +1860,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -1962,7 +1980,7 @@ dependencies = [ "hmac", "lazy_static", "rand_core", - "secp256k1 0.28.0", + "secp256k1 0.28.2", "serde", "serde_json", "sha2", @@ -1973,9 +1991,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -1988,98 +2006,127 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "lightning" version = "0.0.118" -source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=686a84236f54bf8d7270a5fbec07801e5281691f#686a84236f54bf8d7270a5fbec07801e5281691f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52cec5fa9382154fe9671e8df93095b800c7d77abc66e2a5ef839d672521c5e" dependencies = [ "bitcoin 0.29.2", "core2", "hashbrown 0.8.2", +] + +[[package]] +name = "lightning" +version = "0.0.121" +source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=e82635b32458a77d28a5a23b664696422eb526e4#e82635b32458a77d28a5a23b664696422eb526e4" +dependencies = [ + "bitcoin 0.30.2", + "hex-conservative", + "libm", "musig2", ] [[package]] name = "lightning-background-processor" -version = "0.0.118" -source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=686a84236f54bf8d7270a5fbec07801e5281691f#686a84236f54bf8d7270a5fbec07801e5281691f" +version = "0.0.121" +source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=e82635b32458a77d28a5a23b664696422eb526e4#e82635b32458a77d28a5a23b664696422eb526e4" dependencies = [ - "bitcoin 0.29.2", - "lightning", + "bitcoin 0.30.2", + "lightning 0.0.121", "lightning-rapid-gossip-sync", ] [[package]] name = "lightning-invoice" version = "0.26.0" -source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=686a84236f54bf8d7270a5fbec07801e5281691f#686a84236f54bf8d7270a5fbec07801e5281691f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb24878b0f4ef75f020976c886d9ad1503867802329cc963e0ab4623ea3b25c" dependencies = [ "bech32", "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", - "lightning", + "lightning 0.0.118", "num-traits", "secp256k1 0.24.3", "serde", ] +[[package]] +name = "lightning-invoice" +version = "0.29.0" +source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=e82635b32458a77d28a5a23b664696422eb526e4#e82635b32458a77d28a5a23b664696422eb526e4" +dependencies = [ + "bech32", + "bitcoin 0.30.2", + "lightning 0.0.121", + "num-traits", + "secp256k1 0.27.0", + "serde", +] + [[package]] name = "lightning-liquidity" version = "0.1.0" -source = "git+https://github.com/johncantrell97/ldk-lsp-client.git?rev=9e01757d20c04aa31c28de8c4ffab5442d547edc#9e01757d20c04aa31c28de8c4ffab5442d547edc" +source = "git+https://github.com/lightningdevkit/lightning-liquidity.git?rev=478ccf9324e2650d200ea289a0ba8905afe420b6#478ccf9324e2650d200ea289a0ba8905afe420b6" dependencies = [ - "bitcoin 0.29.2", + "bitcoin 0.30.2", "chrono", - "lightning", - "lightning-invoice", + "lightning 0.0.121", + "lightning-invoice 0.29.0", "serde", "serde_json", ] [[package]] name = "lightning-rapid-gossip-sync" -version = "0.0.118" -source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=686a84236f54bf8d7270a5fbec07801e5281691f#686a84236f54bf8d7270a5fbec07801e5281691f" +version = "0.0.121" +source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=e82635b32458a77d28a5a23b664696422eb526e4#e82635b32458a77d28a5a23b664696422eb526e4" dependencies = [ - "bitcoin 0.29.2", - "lightning", + "bitcoin 0.30.2", + "lightning 0.0.121", ] [[package]] name = "lightning-transaction-sync" -version = "0.0.118" -source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=686a84236f54bf8d7270a5fbec07801e5281691f#686a84236f54bf8d7270a5fbec07801e5281691f" +version = "0.0.121" +source = "git+https://github.com/MutinyWallet/rust-lightning.git?rev=e82635b32458a77d28a5a23b664696422eb526e4#e82635b32458a77d28a5a23b664696422eb526e4" dependencies = [ "bdk-macros", - "bitcoin 0.29.2", - "esplora-client", + "bitcoin 0.30.2", + "esplora-client 0.6.0", "futures", - "lightning", - "reqwest", + "lightning 0.0.121", ] [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lnurl-rs" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa42d2e0488393c00b96d0ea170eb6f9acbda7f965690fcd40ce6447517db7" +checksum = "29742339d2d88bd3ea1f4305e11b22d3efada9f86010ccbd7b6646837cc57e85" dependencies = [ "aes", "anyhow", "base64 0.13.1", "bech32", - "bitcoin 0.29.2", - "bitcoin_hashes 0.12.0", + "bitcoin 0.30.2", "cbc", "email_address", "reqwest", @@ -2131,9 +2178,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -2151,24 +2198,35 @@ dependencies = [ "serde", ] +[[package]] +name = "miniscript" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eb102b66b2127a872dbcc73095b7b47aeb9d92f7b03c2b2298253ffc82c7594" +dependencies = [ + "bitcoin 0.30.2", + "bitcoin-private", + "serde", +] + [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2201,9 +2259,9 @@ dependencies = [ [[package]] name = "musig2" version = "0.1.0" -source = "git+https://github.com/arik-so/rust-musig2?rev=27797d7#27797d78cf64e8974e38d7f31ebb11e455015a9e" +source = "git+https://github.com/arik-so/rust-musig2?rev=cff11e3#cff11e3b1af1691f721a120dc6acb921afa31f89" dependencies = [ - "bitcoin 0.29.2", + "bitcoin 0.30.2", ] [[package]] @@ -2214,7 +2272,7 @@ dependencies = [ "aes-gcm", "anyhow", "argon2", - "async-lock 3.2.0", + "async-lock 3.3.0", "async-trait", "base64 0.13.1", "bdk", @@ -2223,11 +2281,11 @@ dependencies = [ "bdk_esplora", "bincode", "bip39", - "bitcoin 0.29.2", + "bitcoin 0.30.2", "cbc", "cfg-if", "chrono", - "esplora-client", + "esplora-client 0.6.0", "fedimint-bip39", "fedimint-client", "fedimint-core", @@ -2239,14 +2297,14 @@ dependencies = [ "futures-util", "getrandom", "gloo-net", - "hex", + "hex-conservative", "instant", "itertools 0.11.0", "js-sys", "jwt-compact", - "lightning", + "lightning 0.0.121", "lightning-background-processor", - "lightning-invoice", + "lightning-invoice 0.29.0", "lightning-liquidity", "lightning-rapid-gossip-sync", "lightning-transaction-sync", @@ -2278,16 +2336,17 @@ dependencies = [ "anyhow", "async-trait", "bip39", - "bitcoin 0.29.2", + "bitcoin 0.30.2", "console_error_panic_hook", "fedimint-core", "futures", "getrandom", "gloo-utils", + "hex-conservative", "instant", "js-sys", - "lightning", - "lightning-invoice", + "lightning 0.0.121", + "lightning-invoice 0.29.0", "lnurl-rs", "log", "mutiny-core", @@ -2343,9 +2402,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e47228d958fd65ef3e04650a3b1dd80f16f10f0243c80ed969556dead0f48c8" dependencies = [ "aes", - "base64 0.21.5", + "base64 0.21.7", "bip39", - "bitcoin 0.30.1", + "bitcoin 0.30.2", "cbc", "chacha20", "getrandom", @@ -2423,9 +2482,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -2444,11 +2503,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.59" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "foreign-types", "libc", @@ -2465,7 +2524,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2476,9 +2535,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.95" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -2503,9 +2562,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ "arrayvec", "bitvec", @@ -2517,9 +2576,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.5" +version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2553,7 +2612,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -2591,7 +2650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7b659f9e4ff06192df5d4504ea7ae866a1680eb2c87e4dca521fb14753eb0e7" dependencies = [ "bip21", - "bitcoin 0.30.1", + "bitcoin 0.30.2", "log", "serde_json", "url", @@ -2611,9 +2670,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percent-encoding-rfc3986" @@ -2633,22 +2692,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2665,9 +2724,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "polyval" @@ -2719,11 +2778,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" dependencies = [ - "once_cell", + "toml_datetime", "toml_edit", ] @@ -2753,18 +2812,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2816,13 +2875,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -2837,9 +2896,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -2860,11 +2919,11 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -2883,11 +2942,12 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.8", + "rustls 0.21.10", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2934,16 +2994,16 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2969,15 +3029,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -2994,12 +3054,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.8" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.5", + "ring 0.17.7", "rustls-webpki", "sct", ] @@ -3010,7 +3070,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.5", + "base64 0.21.7", ] [[package]] @@ -3019,7 +3079,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -3031,17 +3091,17 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -3062,7 +3122,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] @@ -3092,11 +3152,11 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.28.0" +version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "secp256k1-sys 0.9.1", + "secp256k1-sys 0.9.2", ] [[package]] @@ -3119,9 +3179,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" +checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" dependencies = [ "cc", ] @@ -3173,9 +3233,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "send_wrapper" @@ -3191,9 +3251,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.192" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] @@ -3209,22 +3269,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -3316,19 +3376,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "socket2" -version = "0.4.10" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" @@ -3337,7 +3387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3405,15 +3455,21 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3443,15 +3499,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.8.1" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -3462,22 +3518,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3516,9 +3572,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -3528,21 +3584,21 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", "tracing", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3572,7 +3628,7 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.8", + "rustls 0.21.10", "tokio", ] @@ -3610,7 +3666,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.8", + "rustls 0.21.10", "tokio", "tokio-rustls 0.24.1", "tungstenite 0.20.1", @@ -3634,17 +3690,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap", "toml_datetime", "winnow", ] @@ -3674,7 +3730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -3718,9 +3774,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" @@ -3755,7 +3811,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.21.8", + "rustls 0.21.10", "sha1", "thiserror", "url", @@ -3770,9 +3826,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3813,27 +3869,26 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", "serde", ] [[package]] name = "url-fork" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956afc9d7e101f0b718a6776489cd7998d0b17fc79f4cdb6ee6761fb72d1c2ce" +checksum = "7fa3323c39b8e786154d3000b70ae9af0e9bd746c9791456da0d4a1f68ad89d6" dependencies = [ "form_urlencoded", + "idna 0.5.0", "percent-encoding", "serde", - "unicode-bidi", - "unicode-normalization", ] [[package]] @@ -3850,9 +3905,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", ] @@ -3863,7 +3918,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" dependencies = [ - "idna", + "idna 0.4.0", "lazy_static", "regex", "serde", @@ -3934,9 +3989,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3944,24 +3999,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -3971,9 +4026,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3981,28 +4036,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-bindgen-test" -version = "0.3.38" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6433b7c56db97397842c46b67e11873eda263170afeb3a2dc74a7cb370fee0d" +checksum = "139bd73305d50e1c1c4333210c0db43d989395b64a237bd35c10ef3832a7f70c" dependencies = [ "console_error_panic_hook", "js-sys", @@ -4014,13 +4069,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.38" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "493fcbab756bb764fa37e6bee8cec2dd709eb4273d06d0c282a5e74275ded735" +checksum = "70072aebfe5da66d2716002c729a14e4aec4da0e23cc2ea66323dac541c93928" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -4036,9 +4091,9 @@ dependencies = [ [[package]] name = "wasm-ws" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601c6f6340b473083c38e6cdda1f39dfc35d67b0e4b54fa56624d6189c2aa366" +checksum = "f5b3a482e27ff54809c0848629d9033179705c5ea2f58e26cf45dc77c34c4984" dependencies = [ "async_io_stream", "futures", @@ -4053,9 +4108,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.65" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -4067,15 +4122,15 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.5", + "ring 0.17.7", "untrusted 0.9.0", ] [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -4101,11 +4156,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -4114,7 +4169,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -4123,13 +4187,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -4138,47 +4217,89 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" -version = "0.5.28" +version = "0.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +checksum = "a7cad8365489051ae9f054164e459304af2e7e9bb407c958076c8bf4aef52da5" dependencies = [ "memchr", ] @@ -4190,7 +4311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4204,9 +4325,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" dependencies = [ "zeroize_derive", ] @@ -4219,5 +4340,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] diff --git a/Cargo.toml b/Cargo.toml index c459bd9bb..5f16a3e01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ opt-level = "z" opt-level = "z" [patch.crates-io] -lightning = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "686a84236f54bf8d7270a5fbec07801e5281691f" } -lightning-invoice = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "686a84236f54bf8d7270a5fbec07801e5281691f" } -lightning-rapid-gossip-sync = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "686a84236f54bf8d7270a5fbec07801e5281691f" } -lightning-background-processor = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "686a84236f54bf8d7270a5fbec07801e5281691f" } -lightning-transaction-sync = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "686a84236f54bf8d7270a5fbec07801e5281691f" } +lightning = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e82635b32458a77d28a5a23b664696422eb526e4" } +lightning-invoice = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e82635b32458a77d28a5a23b664696422eb526e4" } +lightning-rapid-gossip-sync = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e82635b32458a77d28a5a23b664696422eb526e4" } +lightning-background-processor = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e82635b32458a77d28a5a23b664696422eb526e4" } +lightning-transaction-sync = { git = 'https://github.com/MutinyWallet/rust-lightning.git', rev = "e82635b32458a77d28a5a23b664696422eb526e4" } diff --git a/mutiny-core/Cargo.toml b/mutiny-core/Cargo.toml index 2080865e5..b37b5ae6a 100644 --- a/mutiny-core/Cargo.toml +++ b/mutiny-core/Cargo.toml @@ -12,27 +12,27 @@ homepage = "https://mutinywallet.com" repository = "https://github.com/mutinywallet/mutiny-node" [dependencies] -lnurl-rs = { version = "0.3.1", default-features = false, features = ["async", "async-https"] } +lnurl-rs = { version = "0.4.0", default-features = false, features = ["async", "async-https"] } cfg-if = "1.0.0" bip39 = { version = "2.0.0" } -bitcoin = { version = "0.29.2", default-features = false, features = ["std", "serde", "secp-recovery", "rand"] } -bdk = { version = "=1.0.0-alpha.1" } -bdk_esplora = { version = "=0.3.0", default-features = false, features = ["std", "async-https"] } -bdk_chain = { version = "=0.5.0", features = ["std"] } +bitcoin = { version = "0.30.2", default-features = false, features = ["std", "serde", "secp-recovery", "rand"] } +bdk = { version = "1.0.0-alpha.5" } +bdk_esplora = { version = "0.7.0", default-features = false, features = ["std", "async-https"] } +bdk_chain = { version = "0.9.0", features = ["std"] } bdk-macros = "0.6.0" getrandom = { version = "0.2" } itertools = "0.11.0" serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } uuid = { version = "1.1.2", features = ["v4"] } -esplora-client = { version = "0.5", default-features = false } -lightning = { version = "0.0.118", default-features = false, features = ["max_level_trace", "grind_signatures", "std"] } -lightning-invoice = { version = "0.26.0", features = ["serde"] } -lightning-rapid-gossip-sync = { version = "0.0.118" } -lightning-background-processor = { version = "0.0.118", features = ["futures"] } -lightning-transaction-sync = { version = "0.0.118", features = ["esplora-async-https"] } -lightning-liquidity = { git = "https://github.com/johncantrell97/ldk-lsp-client.git", rev = "9e01757d20c04aa31c28de8c4ffab5442d547edc" } +esplora-client = { version = "0.6", default-features = false } +lightning = { version = "0.0.121", default-features = false, features = ["max_level_trace", "grind_signatures", "std"] } +lightning-invoice = { version = "0.29.0", features = ["serde"] } +lightning-rapid-gossip-sync = { version = "0.0.121" } +lightning-background-processor = { version = "0.0.121", features = ["futures"] } +lightning-transaction-sync = { version = "0.0.121", default-features = false, features = ["esplora-async-https"] } +lightning-liquidity = { git = "https://github.com/lightningdevkit/lightning-liquidity.git", rev = "478ccf9324e2650d200ea289a0ba8905afe420b6" } chrono = "0.4.22" futures-util = { version = "0.3", default-features = false } reqwest = { version = "0.11", default-features = false, features = ["json"] } @@ -46,7 +46,7 @@ jwt-compact = { version = "0.8.0-beta.1", features = ["es256k"] } argon2 = { version = "0.5.0", features = ["password-hash", "alloc"] } payjoin = { version = "0.13.0", features = ["send", "base64"] } bincode = "1.3.3" -hex = "0.4.3" +hex-conservative = "0.1.1" async-lock = "3.2.0" fedimint-client = { git = "https://github.com/fedimint/fedimint", rev = "6a923ee10c3a578cd835044e3fdd94aa5123735a" } diff --git a/mutiny-core/src/error.rs b/mutiny-core/src/error.rs index 5ac21f81f..84c4c368d 100644 --- a/mutiny-core/src/error.rs +++ b/mutiny-core/src/error.rs @@ -1,8 +1,9 @@ use aes::cipher::block_padding::UnpadError; -use bitcoin::Network; +use bdk::signer::SignerError; +use bdk::wallet::error::BuildFeeBumpError; +use bdk::wallet::tx_builder::AddUtxoError; use lightning::ln::channelmanager::RetryableSendFailure; use lightning::ln::peer_handler::PeerHandleError; -use lightning_invoice::payment::PaymentError; use lightning_invoice::ParseOrSemanticError; use lightning_rapid_gossip_sync::GraphSyncError; use lightning_transaction_sync::TxSyncError; @@ -36,7 +37,7 @@ pub enum MutinyError { ConnectionFailed, /// The invoice or address is on a different network #[error("The invoice or address is on a different network.")] - IncorrectNetwork(Network), + IncorrectNetwork, /// Payment of the given invoice has already been initiated. #[error("An invoice must not get payed twice.")] NonUniquePaymentHash, @@ -201,10 +202,11 @@ impl PartialEq for MutinyError { (Self::NotFound, Self::NotFound) => true, (Self::FundingTxCreationFailed, Self::FundingTxCreationFailed) => true, (Self::ConnectionFailed, Self::ConnectionFailed) => true, - (Self::IncorrectNetwork(net), Self::IncorrectNetwork(net2)) => net == net2, + (Self::IncorrectNetwork, Self::IncorrectNetwork) => true, (Self::NonUniquePaymentHash, Self::NonUniquePaymentHash) => true, (Self::PaymentTimeout, Self::PaymentTimeout) => true, (Self::InvoiceInvalid, Self::InvoiceInvalid) => true, + (Self::InvoiceExpired, Self::InvoiceExpired) => true, (Self::InvoiceCreationFailed, Self::InvoiceCreationFailed) => true, (Self::ReserveAmountError, Self::ReserveAmountError) => true, (Self::InsufficientBalance, Self::InsufficientBalance) => true, @@ -285,14 +287,9 @@ impl From for MutinyError { } } -impl From for MutinyError { - fn from(e: bdk::Error) -> Self { - match e { - bdk::Error::Signer(_) => Self::WalletSigningFailed, - bdk::Error::InsufficientFunds { .. } => Self::InsufficientBalance, - bdk::Error::TransactionNotFound => Self::NotFound, - _ => Self::WalletOperationFailed, - } +impl From for MutinyError { + fn from(_e: bdk_chain::local_chain::AlterCheckPointError) -> Self { + Self::WalletOperationFailed } } @@ -305,20 +302,39 @@ impl From for MutinyError { impl From> for MutinyError { fn from(e: bdk::wallet::NewError) -> Self { match e { - bdk::wallet::NewError::Persist(e) => e, + bdk::wallet::NewError::Write(e) => e, bdk::wallet::NewError::Descriptor(e) => e.into(), + bdk::wallet::NewError::NonEmptyDatabase => Self::WalletOperationFailed, + } + } +} + +impl From> for MutinyError { + fn from(e: bdk::wallet::LoadError) -> Self { + match e { + bdk::wallet::LoadError::Descriptor(e) => e.into(), + bdk::wallet::LoadError::Load(e) => e, + bdk::wallet::LoadError::MissingGenesis => Self::WalletOperationFailed, + bdk::wallet::LoadError::MissingNetwork => Self::WalletOperationFailed, + bdk::wallet::LoadError::NotInitialized => Self::WalletOperationFailed, } } } +impl From for MutinyError { + fn from(_: AddUtxoError) -> Self { + Self::WalletOperationFailed + } +} + impl From for MutinyError { fn from(_e: bip39::Error) -> Self { Self::InvalidMnemonic } } -impl From for MutinyError { - fn from(_e: bitcoin::util::bip32::Error) -> Self { +impl From for MutinyError { + fn from(_e: bitcoin::bip32::Error) -> Self { Self::InvalidMnemonic } } @@ -366,15 +382,12 @@ impl From for MutinyError { } } -impl From for MutinyError { - fn from(e: PaymentError) -> Self { - match e { - PaymentError::Invoice(_) => Self::InvoiceInvalid, - PaymentError::Sending(s) => match s { - RetryableSendFailure::PaymentExpired => Self::InvoiceExpired, - RetryableSendFailure::RouteNotFound => Self::RoutingFailed, - RetryableSendFailure::DuplicatePayment => Self::NonUniquePaymentHash, - }, +impl From for MutinyError { + fn from(s: RetryableSendFailure) -> Self { + match s { + RetryableSendFailure::PaymentExpired => Self::InvoiceExpired, + RetryableSendFailure::RouteNotFound => Self::RoutingFailed, + RetryableSendFailure::DuplicatePayment => Self::NonUniquePaymentHash, } } } @@ -427,10 +440,15 @@ impl From for MutinyError { } } -impl From for MutinyError { - fn from(_e: bitcoin::util::address::Error) -> Self { - MutinyError::ReadError { - source: MutinyStorageError::Other(anyhow::anyhow!("Failed to decode address")), +impl From for MutinyError { + fn from(e: bitcoin::address::Error) -> Self { + match e { + bitcoin::address::Error::NetworkValidation { .. } => MutinyError::IncorrectNetwork, + bitcoin::address::Error::UnrecognizedScript => MutinyError::InvalidArgumentsError, + bitcoin::address::Error::UnknownAddressType(_) => MutinyError::InvalidArgumentsError, + _ => MutinyError::ReadError { + source: MutinyStorageError::Other(anyhow::anyhow!("Failed to decode address")), + }, } } } @@ -442,15 +460,33 @@ impl From for MutinyError { } } -impl From for MutinyError { - fn from(_e: bdk_chain::local_chain::InsertBlockNotMatchingError) -> Self { +impl From for MutinyError { + fn from(_e: bdk::wallet::InsertTxError) -> Self { Self::WalletSyncError } } -impl From for MutinyError { - fn from(_e: bdk::wallet::InsertTxError) -> Self { - Self::WalletSyncError +impl From> for MutinyError { + fn from(_e: bdk::wallet::error::CreateTxError) -> Self { + Self::WalletOperationFailed + } +} + +impl From for MutinyError { + fn from(e: BuildFeeBumpError) -> Self { + match e { + BuildFeeBumpError::UnknownUtxo(_) => Self::NotFound, + BuildFeeBumpError::TransactionNotFound(_) => Self::NotFound, + BuildFeeBumpError::TransactionConfirmed(_) => Self::NotFound, + BuildFeeBumpError::IrreplaceableTransaction(_) => Self::InvalidArgumentsError, + BuildFeeBumpError::FeeRateUnavailable => Self::WalletOperationFailed, + } + } +} + +impl From for MutinyError { + fn from(_: SignerError) -> Self { + Self::WalletOperationFailed } } diff --git a/mutiny-core/src/event.rs b/mutiny-core/src/event.rs index a0492c8b8..d5a1cdc7b 100644 --- a/mutiny-core/src/event.rs +++ b/mutiny-core/src/event.rs @@ -9,10 +9,9 @@ use crate::utils::sleep; use crate::{fees::MutinyFeeEstimator, storage::read_payment_info}; use crate::{keymanager::PhantomKeysManager, storage::persist_payment_info}; use anyhow::anyhow; -use bitcoin::hashes::hex::ToHex; +use bitcoin::absolute::LockTime; use bitcoin::secp256k1::PublicKey; use bitcoin::secp256k1::Secp256k1; -use bitcoin::{LockTime, PackedLockTime}; use core::fmt; use lightning::events::{Event, PaymentPurpose}; use lightning::sign::SpendableOutputDescriptor; @@ -175,7 +174,7 @@ impl EventHandler { } }; - let label = format!("LN Channel: {}", counterparty_node_id.to_hex()); + let label = format!("LN Channel: {}", counterparty_node_id); let labels = params_opt .as_ref() .and_then(|p| p.labels.clone()) @@ -238,7 +237,7 @@ impl EventHandler { counterparty_skimmed_fee_msat, .. } => { - log_debug!(self.logger, "EVENT: PaymentReceived received payment from payment hash {} of {amount_msat} millisatoshis to {receiver_node_id:?}", payment_hash.0.to_hex()); + log_debug!(self.logger, "EVENT: PaymentReceived received payment from payment hash {} of {amount_msat} millisatoshis to {receiver_node_id:?}", payment_hash); let expected_skimmed_fee_msat = self .lsp_client @@ -272,7 +271,7 @@ impl EventHandler { htlcs, sender_intended_total_msat, } => { - log_debug!(self.logger, "EVENT: PaymentClaimed claimed payment from payment hash {} of {} millisatoshis ({sender_intended_total_msat:?} intended) from {} htlcs", payment_hash.0.to_hex(), amount_msat, htlcs.len()); + log_debug!(self.logger, "EVENT: PaymentClaimed claimed payment from payment hash {} of {} millisatoshis ({sender_intended_total_msat:?} intended) from {} htlcs", payment_hash, amount_msat, htlcs.len()); let (payment_preimage, payment_secret) = match purpose { PaymentPurpose::InvoicePayment { @@ -345,11 +344,7 @@ impl EventHandler { fee_paid_msat, .. } => { - log_debug!( - self.logger, - "EVENT: PaymentSent: {}", - payment_hash.0.to_hex() - ); + log_debug!(self.logger, "EVENT: PaymentSent: {}", payment_hash); match read_payment_info( &self.persister.storage, @@ -446,11 +441,7 @@ impl EventHandler { log_debug!(self.logger, "EVENT: ProbeFailed, ignored"); } Event::PaymentFailed { payment_hash, .. } => { - log_error!( - self.logger, - "EVENT: PaymentFailed: {}", - payment_hash.0.to_hex() - ); + log_error!(self.logger, "EVENT: PaymentFailed: {}", payment_hash); match read_payment_info( &self.persister.storage, @@ -518,6 +509,7 @@ impl EventHandler { user_channel_id, counterparty_node_id: node_id, channel_capacity_sats, + .. } => { // if we still have channel open params, then it was just a failed channel open // we should not persist this as a closed channel and just delete the channel open params @@ -529,7 +521,7 @@ impl EventHandler { log_debug!( self.logger, "EVENT: Channel {} of size {} closed due to: {:?}", - channel_id.to_hex(), + channel_id, channel_capacity_sats .map(|s| s.to_string()) .unwrap_or_else(|| "unknown".to_string()), @@ -558,9 +550,9 @@ impl EventHandler { log_debug!( self.logger, "EVENT: ChannelReady channel_id: {}, user_channel_id: {}, counterparty_node_id: {}, channel_type: {}", - channel_id.to_hex(), + channel_id, user_channel_id, - counterparty_node_id.to_hex(), + counterparty_node_id, channel_type); } Event::ChannelPending { @@ -572,9 +564,9 @@ impl EventHandler { log_debug!( self.logger, "EVENT: ChannelPending channel_id: {}, user_channel_id: {}, counterparty_node_id: {}", - channel_id.to_hex(), + channel_id, user_channel_id, - counterparty_node_id.to_hex()); + counterparty_node_id); if let Err(e) = self.persister.delete_channel_open_params(user_channel_id) { log_warn!( @@ -592,6 +584,13 @@ impl EventHandler { // we don't support bolt 12 yet log_warn!(self.logger, "EVENT: InvoiceRequestFailed: {payment_id}"); } + Event::ConnectionNeeded { node_id, addresses } => { + // we don't support bolt 12 yet, and we won't have the connection info anyways + log_debug!( + self.logger, + "EVENT: ConnectionNeeded: {node_id} @ {addresses:?}" + ); + } } } @@ -644,7 +643,7 @@ impl EventHandler { height -= u32::from_be_bytes(rand) % 100; } - let locktime = LockTime::from_height(height).map(PackedLockTime::from).ok(); + let locktime = LockTime::from_height(height).ok(); let spending_tx = self .keys_manager diff --git a/mutiny-core/src/federation.rs b/mutiny-core/src/federation.rs index fe787d464..f6e886f10 100644 --- a/mutiny-core/src/federation.rs +++ b/mutiny-core/src/federation.rs @@ -1,4 +1,4 @@ -use crate::utils::spawn; +use crate::utils::{convert_from_fedimint_invoice, convert_to_fedimint_invoice, spawn}; use crate::{ error::{MutinyError, MutinyStorageError}, event::PaymentInfo, @@ -13,11 +13,11 @@ use crate::{ }; use async_trait::async_trait; use bip39::Mnemonic; +use bitcoin::secp256k1::ThirtyTwoByteHash; use bitcoin::{ - hashes::{hex::ToHex, sha256}, + bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}, + hashes::sha256, secp256k1::Secp256k1, - util::bip32::ExtendedPrivKey, - util::bip32::{ChildNumber, DerivationPath}, Network, }; use core::fmt; @@ -50,18 +50,19 @@ use fedimint_ln_client::{ InternalPayState, LightningClientInit, LightningClientModule, LightningOperationMeta, LightningOperationMetaVariant, LnPayState, LnReceiveState, }; +use fedimint_ln_common::lightning_invoice::RoutingFees; use fedimint_ln_common::LightningCommonInit; use fedimint_mint_client::MintClientInit; use fedimint_wallet_client::{WalletClientInit, WalletClientModule}; use futures::future::{self}; use futures_util::{pin_mut, StreamExt}; -use hex::FromHex; +use hex_conservative::{DisplayHex, FromHex}; #[cfg(target_arch = "wasm32")] use instant::Instant; use lightning::{ ln::PaymentHash, log_debug, log_error, log_info, log_trace, log_warn, util::logger::Logger, }; -use lightning_invoice::{Bolt11Invoice, RoutingFees}; +use lightning_invoice::Bolt11Invoice; use serde::{de::DeserializeOwned, Deserialize, Serialize}; #[cfg(not(target_arch = "wasm32"))] use std::time::Instant; @@ -246,7 +247,8 @@ impl FederationClient { // check federation is on expected network let wallet_client = fedimint_client.get_first_module::(); - if network != wallet_client.get_network() { + // compare magic bytes because different versions of rust-bitcoin + if network.magic().to_bytes() != wallet_client.get_network().magic().to_le_bytes() { log_error!( logger, "Fedimint on different network {}, expected: {network}", @@ -325,6 +327,7 @@ impl FederationClient { let (_id, invoice) = lightning_module .create_bolt11_invoice(Amount::from_sats(amount), String::new(), None, ()) .await?; + let invoice = convert_from_fedimint_invoice(&invoice); // persist the invoice let mut stored_payment: MutinyInvoice = invoice.clone().into(); @@ -332,7 +335,7 @@ impl FederationClient { stored_payment.labels = labels; log_trace!(self.logger, "Persiting payment"); - let hash = *stored_payment.payment_hash.as_inner(); + let hash = stored_payment.payment_hash.into_32(); let payment_info = PaymentInfo::from(stored_payment); persist_payment_info(&self.storage, &hash, &payment_info, inbound)?; log_trace!(self.logger, "Persisted payment"); @@ -392,9 +395,9 @@ impl FederationClient { ); let mut operation_map: HashMap< - sha256::Hash, + [u8; 32], (ChronologicalOperationLogKey, OperationLogEntry), - > = HashMap::new(); + > = HashMap::with_capacity(operations.len()); log_trace!( self.logger, "About to go through {} operations", @@ -405,10 +408,12 @@ impl FederationClient { let lightning_meta: LightningOperationMeta = entry.meta(); match lightning_meta.variant { LightningOperationMetaVariant::Pay(pay_meta) => { - operation_map.insert(*pay_meta.invoice.payment_hash(), (key, entry)); + let hash = pay_meta.invoice.payment_hash().into_inner(); + operation_map.insert(hash, (key, entry)); } LightningOperationMetaVariant::Receive { invoice, .. } => { - operation_map.insert(*invoice.payment_hash(), (key, entry)); + let hash = invoice.payment_hash().into_inner(); + operation_map.insert(hash, (key, entry)); } } } @@ -420,12 +425,12 @@ impl FederationClient { pending_invoices.len() ); for invoice in pending_invoices { - let hash = invoice.payment_hash; + let hash = invoice.payment_hash.into_32(); if let Some((key, entry)) = operation_map.get(&hash) { if let Some(updated_invoice) = extract_invoice_from_entry( self.logger.clone(), entry, - &hash, + hash, key.operation_id, &lightning_module, ) @@ -449,7 +454,7 @@ impl FederationClient { HTLCStatus::Succeeded | HTLCStatus::Failed ) { log_debug!(self.logger, "Saving updated payment"); - let hash = *updated_invoice.payment_hash.as_inner(); + let hash = updated_invoice.payment_hash.into_32(); let inbound = updated_invoice.inbound; let payment_info = PaymentInfo::from(updated_invoice); persist_payment_info(&self.storage, &hash, &payment_info, inbound)?; @@ -497,7 +502,7 @@ impl FederationClient { if let Some(updated_invoice) = extract_invoice_from_entry( self.logger.clone(), &entry, - hash, + hash.into_32(), key.operation_id, &lightning_module, ) @@ -519,7 +524,7 @@ impl FederationClient { // If the invoice is not InFlight or Pending, return it directly log_trace!(self.logger, "returning final invoice"); // TODO labels - return MutinyInvoice::from(invoice, PaymentHash(hash.into_inner()), inbound, vec![]); + return MutinyInvoice::from(invoice, PaymentHash(hash.into_32()), inbound, vec![]); } log_debug!(self.logger, "could not find invoice"); @@ -537,15 +542,16 @@ impl FederationClient { .fedimint_client .get_first_module::(); + let fedimint_invoice = convert_to_fedimint_invoice(&invoice); let outgoing_payment = lightning_module - .pay_bolt11_invoice(invoice.clone(), ()) + .pay_bolt11_invoice(fedimint_invoice, ()) .await?; // Save after payment was initiated successfully let mut stored_payment: MutinyInvoice = invoice.clone().into(); stored_payment.inbound = inbound; stored_payment.labels = labels; - let hash = *stored_payment.payment_hash.as_inner(); + let hash = stored_payment.payment_hash.into_32(); let payment_info = PaymentInfo::from(stored_payment); persist_payment_info(&self.storage, &hash, &payment_info, inbound)?; @@ -638,13 +644,15 @@ fn sats_round_up(amount: &Amount) -> u64 { fn get_gateway_preference( gateways: Vec, federation_id: FederationId, -) -> Option { - let mut active_choice: Option = None; +) -> Option { + let mut active_choice: Option = None; let signet_gateway_id = - bitcoin::secp256k1::PublicKey::from_str(SIGNET_GATEWAY).expect("should be valid pubkey"); + fedimint_ln_common::bitcoin::secp256k1::PublicKey::from_str(SIGNET_GATEWAY) + .expect("should be valid pubkey"); let mainnet_gateway_id = - bitcoin::secp256k1::PublicKey::from_str(MAINNET_GATEWAY).expect("should be valid pubkey"); + fedimint_ln_common::bitcoin::secp256k1::PublicKey::from_str(MAINNET_GATEWAY) + .expect("should be valid pubkey"); let signet_federation_id = FederationId::from_str(SIGNET_FEDERATION).expect("should be a valid federation id"); let mainnet_federation_id = @@ -713,7 +721,7 @@ pub(crate) fn mnemonic_from_xpriv(xpriv: ExtendedPrivKey) -> Result, entry: &OperationLogEntry, - hash: &sha256::Hash, + hash: [u8; 32], operation_id: OperationId, lightning_module: &LightningClientModule, ) -> Option { @@ -721,27 +729,29 @@ async fn extract_invoice_from_entry( match lightning_meta.variant { LightningOperationMetaVariant::Pay(pay_meta) => { - if pay_meta.invoice.payment_hash() == hash { + let invoice = convert_from_fedimint_invoice(&pay_meta.invoice); + if invoice.payment_hash().into_32() == hash { match lightning_module.subscribe_ln_pay(operation_id).await { Ok(o) => Some( process_outcome( o, process_pay_state_ln, - pay_meta.invoice, + invoice, false, FEDIMINT_STATUS_TIMEOUT_CHECK_MS, logger, ) .await, ), - Err(_) => Some(pay_meta.invoice.into()), + Err(_) => Some(invoice.into()), } } else { None } } LightningOperationMetaVariant::Receive { invoice, .. } => { - if invoice.payment_hash() == hash { + let invoice = convert_from_fedimint_invoice(&invoice); + if invoice.payment_hash().into_32() == hash { match lightning_module.subscribe_ln_receive(operation_id).await { Ok(o) => Some( process_outcome( @@ -765,7 +775,7 @@ async fn extract_invoice_from_entry( fn process_pay_state_internal(pay_state: InternalPayState, invoice: &mut MutinyInvoice) { invoice.preimage = if let InternalPayState::Preimage(ref preimage) = pay_state { - Some(preimage.0.to_hex()) + Some(preimage.0.to_lower_hex_string()) } else { None }; @@ -971,7 +981,7 @@ impl<'a, S: MutinyStorage> IRawDatabaseTransaction for IndexedDBPseudoTransactio self.mem.commit_tx().await?; let serialized_data = bincode::serialize(&key_value_pairs).map_err(anyhow::Error::new)?; - let hex_serialized_data = hex::encode(serialized_data); + let hex_serialized_data = serialized_data.to_lower_hex_string(); let old = self.federation_version.fetch_add(1, Ordering::SeqCst); let version = old + 1; @@ -1093,27 +1103,28 @@ fn fedimint_mnemonic_generation() { #[cfg(test)] fn gateway_preference() { use fedimint_core::util::SafeUrl; + use fedimint_ln_common::bitcoin::secp256k1::PublicKey; use fedimint_ln_common::{LightningGateway, LightningGatewayAnnouncement}; use std::time::Duration; use super::*; const RANDOM_KEY: &str = "0218845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"; - let random_key = bitcoin::secp256k1::PublicKey::from_str(RANDOM_KEY).unwrap(); + let random_key = PublicKey::from_str(RANDOM_KEY).unwrap(); const VETTED_GATEWAY: &str = "02465ed5be53d04fde66c9418ff14a5f2267723810176c9212b722e542dc1afb1b"; - let vetted_gateway_pubkey = bitcoin::secp256k1::PublicKey::from_str(VETTED_GATEWAY).unwrap(); + let vetted_gateway_pubkey = PublicKey::from_str(VETTED_GATEWAY).unwrap(); const UNVETTED_GATEWAY_KEY_HIGH_FEE: &str = "0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"; let unvetted_gateway_high_fee_pubkey = - bitcoin::secp256k1::PublicKey::from_str(UNVETTED_GATEWAY_KEY_HIGH_FEE).unwrap(); + PublicKey::from_str(UNVETTED_GATEWAY_KEY_HIGH_FEE).unwrap(); const UNVETTED_GATEWAY_KEY_LOW_FEE: &str = "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"; let unvetted_gateway_low_fee_pubkey = - bitcoin::secp256k1::PublicKey::from_str(UNVETTED_GATEWAY_KEY_LOW_FEE).unwrap(); + PublicKey::from_str(UNVETTED_GATEWAY_KEY_LOW_FEE).unwrap(); let random_federation_id = FederationId::dummy(); @@ -1121,7 +1132,7 @@ fn gateway_preference() { let signet_gateway = LightningGatewayAnnouncement { info: LightningGateway { mint_channel_id: 12345, - gateway_redeem_key: bitcoin::secp256k1::PublicKey::from_str(SIGNET_GATEWAY).unwrap(), + gateway_redeem_key: PublicKey::from_str(SIGNET_GATEWAY).unwrap(), node_pub_key: random_key, lightning_alias: "Signet Gateway".to_string(), api: SafeUrl::parse("http://localhost:8080").unwrap(), @@ -1130,7 +1141,7 @@ fn gateway_preference() { base_msat: 100, proportional_millionths: 10, }, - gateway_id: bitcoin::secp256k1::PublicKey::from_str(SIGNET_GATEWAY).unwrap(), + gateway_id: PublicKey::from_str(SIGNET_GATEWAY).unwrap(), supports_private_payments: true, }, vetted: false, @@ -1140,7 +1151,7 @@ fn gateway_preference() { let mainnet_gateway = LightningGatewayAnnouncement { info: LightningGateway { mint_channel_id: 12345, - gateway_redeem_key: bitcoin::secp256k1::PublicKey::from_str(MAINNET_GATEWAY).unwrap(), + gateway_redeem_key: PublicKey::from_str(MAINNET_GATEWAY).unwrap(), node_pub_key: random_key, lightning_alias: "Mainnet Gateway".to_string(), api: SafeUrl::parse("http://localhost:8080").unwrap(), @@ -1149,7 +1160,7 @@ fn gateway_preference() { base_msat: 100, proportional_millionths: 10, }, - gateway_id: bitcoin::secp256k1::PublicKey::from_str(MAINNET_GATEWAY).unwrap(), + gateway_id: PublicKey::from_str(MAINNET_GATEWAY).unwrap(), supports_private_payments: true, }, vetted: false, @@ -1225,13 +1236,13 @@ fn gateway_preference() { let signet_federation_id = FederationId::from_str(SIGNET_FEDERATION).unwrap(); assert_eq!( get_gateway_preference(gateways.clone(), signet_federation_id), - Some(bitcoin::secp256k1::PublicKey::from_str(SIGNET_GATEWAY).unwrap()) + Some(PublicKey::from_str(SIGNET_GATEWAY).unwrap()) ); let mainnet_federation_id = FederationId::from_str(MAINNET_FEDERATION).unwrap(); assert_eq!( get_gateway_preference(gateways.clone(), mainnet_federation_id), - Some(bitcoin::secp256k1::PublicKey::from_str(MAINNET_GATEWAY).unwrap()) + Some(PublicKey::from_str(MAINNET_GATEWAY).unwrap()) ); // Test that the method returns the first vetted gateway if none of the gateways match the federation ID diff --git a/mutiny-core/src/fees.rs b/mutiny-core/src/fees.rs index 07ada14c9..2a5eb720e 100644 --- a/mutiny-core/src/fees.rs +++ b/mutiny-core/src/fees.rs @@ -2,7 +2,7 @@ use crate::logging::MutinyLogger; use crate::storage::MutinyStorage; use crate::{error::MutinyError, utils}; use bdk::FeeRate; -use bitcoin::Network; +use bitcoin::Weight; use esplora_client::AsyncClient; use futures::lock::Mutex; use lightning::chain::chaininterface::{ @@ -25,7 +25,6 @@ pub(crate) const TAPROOT_OUTPUT_SIZE: usize = 43; #[derive(Clone)] pub struct MutinyFeeEstimator { storage: S, - network: Network, esplora: Arc, logger: Arc, last_fee_update_time_secs: Arc>>, @@ -34,13 +33,11 @@ pub struct MutinyFeeEstimator { impl MutinyFeeEstimator { pub fn new( storage: S, - network: Network, esplora: Arc, logger: Arc, ) -> MutinyFeeEstimator { MutinyFeeEstimator { storage, - network, esplora, logger, last_fee_update_time_secs: Arc::new(Mutex::new(None)), @@ -69,7 +66,9 @@ impl MutinyFeeEstimator { // Calculate the transaction weight (non_witness_size * 4) + witness_size }; - FeeRate::from_sat_per_kwu(sats_per_kw as f32).fee_wu(expected_weight) + + FeeRate::from_sat_per_kwu(sats_per_kw as f32) + .fee_wu(Weight::from_wu(expected_weight as u64)) } async fn get_last_sync_time(&self) -> Option { @@ -190,14 +189,6 @@ impl FeeEstimator for MutinyFeeEstimator { // any post processing we do after the we get the fee rate from the cache match confirmation_target { - ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => { - // multiply by 30 to help prevent force closes - // multiply by 100 on test networks because CLN sucks - match self.network { - Network::Bitcoin => fee * 30, - _ => fee * 100, - } - } ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => fee - 250, // helps with rounding errors _ => fee, } @@ -211,7 +202,6 @@ fn num_blocks_from_conf_target(confirmation_target: ConfirmationTarget) -> usize ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => 1008, ConfirmationTarget::ChannelCloseMinimum => 1008, ConfirmationTarget::NonAnchorChannelFee => 6, - ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => 1, ConfirmationTarget::OnChainSweep => 1, } } @@ -223,7 +213,6 @@ fn fallback_fee_from_conf_target(confirmation_target: ConfirmationTarget) -> u32 ConfirmationTarget::ChannelCloseMinimum => 10 * 250, ConfirmationTarget::AnchorChannelFee => 10 * 250, ConfirmationTarget::NonAnchorChannelFee => 20 * 250, - ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => 50 * 250, ConfirmationTarget::OnChainSweep => 50 * 250, } } @@ -250,7 +239,7 @@ mod test { ); let logger = Arc::new(MutinyLogger::default()); - MutinyFeeEstimator::new(storage, Network::Bitcoin, esplora, logger) + MutinyFeeEstimator::new(storage, esplora, logger) } #[test] diff --git a/mutiny-core/src/gossip.rs b/mutiny-core/src/gossip.rs index 02079d919..cfc52f1d8 100644 --- a/mutiny-core/src/gossip.rs +++ b/mutiny-core/src/gossip.rs @@ -2,8 +2,9 @@ use crate::{ node::decay_params, scorer::{HubPreferentialScorer, ProbScorer}, }; -use bitcoin::hashes::hex::{FromHex, ToHex}; +use bitcoin::hashes::hex::FromHex; use bitcoin::Network; +use hex_conservative::DisplayHex; #[cfg(target_arch = "wasm32")] use instant::Instant; use lightning::ln::msgs::NodeAnnouncement; @@ -353,7 +354,7 @@ impl From for LnPeerMetadata { Self { connection_string: None, // todo get from addresses alias: Some(value.contents.alias.to_string()), - color: Some(value.contents.rgb.to_hex()), + color: Some(value.contents.rgb.to_lower_hex_string()), label: None, timestamp: Some(value.contents.timestamp), nodes: vec![], @@ -378,8 +379,9 @@ pub(crate) fn get_all_peers( for (key, value) in all { // remove the prefix from the key let key = key.replace(LN_PEER_METADATA_KEY_PREFIX, ""); - let node_id = NodeId::from_str(&key)?; - peers.insert(node_id, value); + if let Ok(node_id) = NodeId::from_str(&key) { + peers.insert(node_id, value); + } } Ok(peers) } @@ -501,6 +503,7 @@ pub(crate) fn get_rgs_url( "https://rgs.mutinynet.com/snapshot/{last_sync_time}" )), Network::Regtest => None, + net => unreachable!("Unknown network {net}!"), } } } diff --git a/mutiny-core/src/key.rs b/mutiny-core/src/key.rs index dc6d845e3..cb0477a55 100644 --- a/mutiny-core/src/key.rs +++ b/mutiny-core/src/key.rs @@ -1,6 +1,6 @@ use bitcoin::{ + bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}, secp256k1::Secp256k1, - util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}, }; use crate::error::MutinyError; diff --git a/mutiny-core/src/keymanager.rs b/mutiny-core/src/keymanager.rs index b40dc7a85..65163282f 100644 --- a/mutiny-core/src/keymanager.rs +++ b/mutiny-core/src/keymanager.rs @@ -5,13 +5,14 @@ use crate::{error::MutinyError, key::create_root_child_key}; use crate::{key::ChildKey, labels::LabelStorage}; use bdk::wallet::AddressIndex; use bip39::Mnemonic; +use bitcoin::absolute::LockTime; use bitcoin::bech32::u5; +use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::secp256k1::ecdsa::Signature; use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, Signing}; -use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; -use bitcoin::{PackedLockTime, Script, Transaction, TxOut}; +use bitcoin::{ScriptBuf, Transaction, TxOut}; use lightning::ln::msgs::{DecodeError, UnsignedGossipMessage}; use lightning::ln::script::ShutdownScript; use lightning::log_warn; @@ -63,7 +64,7 @@ impl PhantomKeysManager { descriptors: &[&SpendableOutputDescriptor], outputs: Vec, feerate_sat_per_1000_weight: u32, - locktime: Option, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result { let address = { @@ -71,7 +72,8 @@ impl PhantomKeysManager { // These often fail because we continually retry these. Use LastUnused so we don't generate a ton of new // addresses for no reason. wallet - .get_internal_address(AddressIndex::LastUnused) + .try_get_internal_address(AddressIndex::LastUnused) + .map_err(|_| ())? .address }; @@ -157,7 +159,7 @@ impl NodeSigner for PhantomKeysManager { } impl SignerProvider for PhantomKeysManager { - type Signer = InMemorySigner; + type EcdsaSigner = InMemorySigner; fn generate_channel_keys_id( &self, @@ -173,19 +175,20 @@ impl SignerProvider for PhantomKeysManager { &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::Signer { + ) -> Self::EcdsaSigner { self.inner .derive_channel_signer(channel_value_satoshis, channel_keys_id) } - fn read_chan_signer(&self, reader: &[u8]) -> Result { + fn read_chan_signer(&self, reader: &[u8]) -> Result { self.inner.read_chan_signer(reader) } - fn get_destination_script(&self) -> Result { + fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { let mut wallet = self.wallet.wallet.try_write().map_err(|_| ())?; Ok(wallet - .get_address(AddressIndex::New) + .try_get_address(AddressIndex::New) + .map_err(|_| ())? .address .script_pubkey()) } @@ -193,7 +196,8 @@ impl SignerProvider for PhantomKeysManager { fn get_shutdown_scriptpubkey(&self) -> Result { let mut wallet = self.wallet.wallet.try_write().map_err(|_| ())?; let script = wallet - .get_address(AddressIndex::New) + .try_get_address(AddressIndex::New) + .map_err(|_| ())? .address .script_pubkey(); ShutdownScript::try_from(script).map_err(|_| ()) @@ -270,7 +274,7 @@ mod tests { use crate::onchain::OnChainWallet; use crate::storage::MemoryStorage; use bip39::Mnemonic; - use bitcoin::util::bip32::ExtendedPrivKey; + use bitcoin::bip32::ExtendedPrivKey; use bitcoin::Network; use esplora_client::Builder; use std::str::FromStr; @@ -295,7 +299,6 @@ mod tests { let logger = Arc::new(MutinyLogger::default()); let fees = Arc::new(MutinyFeeEstimator::new( db.clone(), - network, esplora.clone(), logger.clone(), )); diff --git a/mutiny-core/src/labels.rs b/mutiny-core/src/labels.rs index 54b81431f..da5db7faa 100644 --- a/mutiny-core/src/labels.rs +++ b/mutiny-core/src/labels.rs @@ -8,7 +8,7 @@ use lnurl::lnurl::LnUrl; use nostr::{key::XOnlyPublicKey, Metadata}; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::str::FromStr; use uuid::Uuid; @@ -17,10 +17,10 @@ const INVOICE_LABELS_MAP_KEY: &str = "invoice_labels"; const LABEL_PREFIX: &str = "label/"; const CONTACT_PREFIX: &str = "contact/"; -#[derive(Debug, Clone, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash, Default)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)] pub struct LabelItem { /// List of addresses that have this label - pub addresses: Vec
, + pub addresses: HashSet, /// List of invoices that have this label pub invoices: Vec, /// Epoch time in seconds when this label was last used @@ -92,7 +92,7 @@ impl Contact { } } -#[derive(Debug, Clone, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd, Hash)] +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] pub enum TagItem { Label((String, LabelItem)), Contact((String, Contact)), @@ -200,9 +200,7 @@ impl LabelStorage for S { Some(mut label_item) => { // Add the address to the label item // and sort so we can dedup the addresses - label_item.addresses.push(address.clone()); - label_item.addresses.sort(); - label_item.addresses.dedup(); + label_item.addresses.insert(address.to_string()); // Update the last used timestamp label_item.last_used_time = now; @@ -217,9 +215,11 @@ impl LabelStorage for S { self.set_data(key, label_item, None)?; } None => { + let mut addresses = HashSet::with_capacity(1); + addresses.insert(address.to_string()); // Create a new label item let label_item = LabelItem { - addresses: vec![address.clone()], + addresses, invoices: vec![], last_used_time: now, }; @@ -268,7 +268,7 @@ impl LabelStorage for S { None => { // Create a new label item let label_item = LabelItem { - addresses: vec![], + addresses: HashSet::new(), invoices: vec![invoice.clone()], last_used_time: now, }; @@ -499,6 +499,7 @@ mod tests { use super::*; use crate::test_utils::*; use bitcoin::Address; + use itertools::Itertools; use lightning_invoice::Bolt11Invoice; use std::collections::HashMap; use std::str::FromStr; @@ -549,14 +550,16 @@ mod tests { labels.insert( "test1".to_string(), LabelItem { - addresses: vec![Address::from_str("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa").unwrap()], + addresses: HashSet::from_iter(vec![ + "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".to_string() + ]), ..Default::default() }, ); labels.insert( "test2".to_string(), LabelItem { - addresses: vec![Address::from_str("1BitcoinEaterAddressDontSendf59kuE").unwrap()], + addresses: HashSet::from_iter(vec!["1BitcoinEaterAddressDontSendf59kuE".to_string()]), invoices: vec![Bolt11Invoice::from_str("lnbc923720n1pj9nr6zpp5xmvlq2u5253htn52mflh2e6gn7pk5ht0d4qyhc62fadytccxw7hqhp5l4s6qwh57a7cwr7zrcz706qx0qy4eykcpr8m8dwz08hqf362egfscqzzsxqzfvsp5pr7yjvcn4ggrf6fq090zey0yvf8nqvdh2kq7fue0s0gnm69evy6s9qyyssqjyq0fwjr22eeg08xvmz88307yqu8tqqdjpycmermks822fpqyxgshj8hvnl9mkh6srclnxx0uf4ugfq43d66ak3rrz4dqcqd23vxwpsqf7dmhm").unwrap()], ..Default::default() }, @@ -564,7 +567,9 @@ mod tests { labels.insert( "test3".to_string(), LabelItem { - addresses: vec![Address::from_str("12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S").unwrap()], + addresses: HashSet::from_iter(vec![ + "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S".to_string() + ]), ..Default::default() }, ); @@ -692,7 +697,7 @@ mod tests { let storage = MemoryStorage::default(); - let address = Address::from_str(ADDRESS).unwrap(); + let address = Address::from_str(ADDRESS).unwrap().assume_checked(); let labels = vec!["label1".to_string(), "label2".to_string()]; let result = storage.set_address_labels(address.clone(), labels.clone()); @@ -814,7 +819,7 @@ mod tests { storage .set_invoice_labels(invoice.clone(), vec![id.clone()]) .unwrap(); - let address = Address::from_str(ADDRESS).unwrap(); + let address = Address::from_str(ADDRESS).unwrap().assume_checked(); storage .set_address_labels(address, vec![id.clone()]) .unwrap(); @@ -846,7 +851,7 @@ mod tests { let storage = MemoryStorage::default(); - let address = Address::from_str(ADDRESS).unwrap(); + let address = Address::from_str(ADDRESS).unwrap().assume_checked(); let invoice = Bolt11Invoice::from_str(INVOICE).unwrap(); let label = "test_label".to_string(); let other_label = "other_label".to_string(); @@ -870,7 +875,10 @@ mod tests { let label_item = storage.get_label(&new_label).unwrap(); assert!(label_item.is_some()); assert_eq!(label_item.clone().unwrap().invoices, vec![invoice]); - assert_eq!(label_item.unwrap().addresses, vec![address]); + assert_eq!( + label_item.unwrap().addresses.into_iter().collect_vec(), + vec![address.to_string()] + ); // check we properly converted the old label to a new label // check we also kept the other label @@ -931,13 +939,18 @@ mod tests { expected_tag_items.push(TagItem::Label((label, label_item))); } - let mut result = storage.get_tag_items().unwrap(); + let result = storage.get_tag_items().unwrap(); - // Sort the resulting vectors to ensure proper comparison - result.sort(); - expected_tag_items.sort(); + // check they have same items + if result.len() != expected_tag_items.len() { + panic!("Incorrect tag items length") + } - assert_eq!(result, expected_tag_items); + for item in expected_tag_items { + if !result.contains(&item) { + panic!("Tag item missing! {item:?}") + } + } } #[test] @@ -952,7 +965,7 @@ mod tests { assert_eq!(contact.last_used, 0); let id = storage.create_new_contact(contact.clone()).unwrap(); - let address = Address::from_str(ADDRESS).unwrap(); + let address = Address::from_str(ADDRESS).unwrap().assume_checked(); storage .set_address_labels(address, vec![id.clone()]) diff --git a/mutiny-core/src/ldkstorage.rs b/mutiny-core/src/ldkstorage.rs index f3a9786a7..863da25ac 100644 --- a/mutiny-core/src/ldkstorage.rs +++ b/mutiny-core/src/ldkstorage.rs @@ -11,12 +11,13 @@ use crate::utils; use crate::utils::{sleep, spawn}; use crate::{chain::MutinyChain, scorer::HubPreferentialScorer}; use anyhow::anyhow; -use bitcoin::hashes::hex::{FromHex, ToHex}; +use bitcoin::hashes::hex::FromHex; use bitcoin::Network; use bitcoin::{BlockHash, Transaction}; use esplora_client::AsyncClient; use futures::{try_join, TryFutureExt}; use futures_util::lock::Mutex; +use hex_conservative::DisplayHex; use lightning::chain::chainmonitor::{MonitorUpdateId, Persist}; use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate}; use lightning::chain::transaction::OutPoint; @@ -25,7 +26,7 @@ use lightning::io::Cursor; use lightning::ln::channelmanager::{ self, ChainParameters, ChannelManager as LdkChannelManager, ChannelManagerReadArgs, }; -use lightning::sign::{InMemorySigner, SpendableOutputDescriptor, WriteableEcdsaChannelSigner}; +use lightning::sign::{InMemorySigner, SpendableOutputDescriptor}; use lightning::util::logger::Logger; use lightning::util::persist::Persister; use lightning::util::ser::{Readable, ReadableArgs, Writeable}; @@ -91,8 +92,7 @@ impl MutinyNodePersister { pub(crate) fn get_monitor_key(&self, funding_txo: &OutPoint) -> String { let key = format!( "{MONITORS_PREFIX_KEY}{}_{}", - funding_txo.txid.to_hex(), - funding_txo.index + funding_txo.txid, funding_txo.index ); self.get_key(&key) } @@ -365,7 +365,7 @@ impl MutinyNodePersister { ) -> Result<(), MutinyError> { let key = self.get_key(&format!( "{CHANNEL_CLOSURE_PREFIX}{}", - user_channel_id.to_be_bytes().to_hex() + user_channel_id.to_be_bytes().to_lower_hex_string() )); self.storage.set_data(key, closure, None)?; Ok(()) @@ -377,7 +377,7 @@ impl MutinyNodePersister { ) -> Result, MutinyError> { let key = self.get_key(&format!( "{CHANNEL_CLOSURE_PREFIX}{}", - user_channel_id.to_be_bytes().to_hex() + user_channel_id.to_be_bytes().to_lower_hex_string() )); self.storage.get_data(key) } @@ -420,7 +420,7 @@ impl MutinyNodePersister { // convert the failed descriptors to hex let failed_hex: Vec = failed .into_iter() - .map(|desc| desc.encode().to_hex()) + .map(|desc| desc.encode().to_lower_hex_string()) .collect(); // add the new descriptors @@ -444,7 +444,7 @@ impl MutinyNodePersister { // convert the failed descriptors to hex let descriptors_hex: Vec = descriptors .into_iter() - .map(|desc| desc.encode().to_hex()) + .map(|desc| desc.encode().to_lower_hex_string()) .collect(); self.storage.set_data(key, descriptors_hex, None)?; @@ -572,7 +572,7 @@ impl let value = VersionedValue { version, - value: serde_json::to_value(channel_manager.encode().to_hex()).unwrap(), + value: serde_json::to_value(channel_manager.encode().to_lower_hex_string()).unwrap(), }; self.storage @@ -588,20 +588,18 @@ impl &self, scorer: &utils::Mutex, ) -> Result<(), lightning::io::Error> { - let scorer_str = scorer.encode().to_hex(); + let scorer_str = scorer.encode().to_lower_hex_string(); self.storage .set_data(PROB_SCORER_KEY.to_string(), scorer_str, None) .map_err(|_| lightning::io::ErrorKind::Other.into()) } } -impl Persist - for MutinyNodePersister -{ +impl Persist for MutinyNodePersister { fn persist_new_channel( &self, funding_txo: OutPoint, - monitor: &ChannelMonitor, + monitor: &ChannelMonitor, monitor_update_id: MonitorUpdateId, ) -> ChannelMonitorUpdateStatus { let key = self.get_monitor_key(&funding_txo); @@ -628,7 +626,7 @@ impl Persist, - monitor: &ChannelMonitor, + monitor: &ChannelMonitor, monitor_update_id: MonitorUpdateId, ) -> ChannelMonitorUpdateStatus { let key = self.get_monitor_key(&funding_txo); @@ -693,9 +691,9 @@ mod test { use crate::{node::scoring_params, storage::persist_payment_info}; use crate::{onchain::OnChainWallet, storage::read_payment_info}; use bip39::Mnemonic; + use bitcoin::bip32::ExtendedPrivKey; use bitcoin::hashes::Hash; use bitcoin::secp256k1::PublicKey; - use bitcoin::util::bip32::ExtendedPrivKey; use bitcoin::Txid; use esplora_client::Builder; use lightning::routing::scoring::ProbabilisticScoringDecayParameters; @@ -719,6 +717,30 @@ mod test { MutinyNodePersister::new(id, storage, Arc::new(MutinyLogger::default())) } + #[test] + fn test_get_monitor_key() { + let test_name = "test_get_monitor_key"; + log!("{}", test_name); + + let persister = get_test_persister(); + let outpoint = OutPoint { + txid: Txid::from_str( + "465ed5be53d04fde66c9418ff14a5f2267723810176c9212b722e542dc1afb1b", + ) + .unwrap(), + index: 0, + }; + let key = persister.get_monitor_key(&outpoint); + + assert_eq!( + key, + format!( + "monitors/465ed5be53d04fde66c9418ff14a5f2267723810176c9212b722e542dc1afb1b_0_{}", + persister.node_id + ) + ); + } + #[test] fn test_persist_payment_info() { let test_name = "test_persist_payment_info"; @@ -816,6 +838,7 @@ mod test { index: 0, }, output: Default::default(), + channel_keys_id: None, }; let result = persister.persist_failed_spendable_outputs(vec![static_output_0.clone()]); assert!(result.is_ok()); @@ -829,6 +852,7 @@ mod test { index: 1, }, output: Default::default(), + channel_keys_id: None, }; let result = persister.persist_failed_spendable_outputs(vec![static_output_1.clone()]); assert!(result.is_ok()); @@ -877,7 +901,6 @@ mod test { let esplora = Arc::new(Builder::new(&esplora_server_url).build_async().unwrap()); let fees = Arc::new(MutinyFeeEstimator::new( persister.storage.clone(), - network, esplora.clone(), logger.clone(), )); diff --git a/mutiny-core/src/lib.rs b/mutiny-core/src/lib.rs index f40b671d9..82a750954 100644 --- a/mutiny-core/src/lib.rs +++ b/mutiny-core/src/lib.rs @@ -79,13 +79,13 @@ use ::nostr::{Event, EventId, JsonUtil, Kind}; use async_lock::RwLock; use bdk_chain::ConfirmationTime; use bip39::Mnemonic; -use bitcoin::hashes::hex::ToHex; -use bitcoin::hashes::{sha256, Hash}; +use bitcoin::bip32::ExtendedPrivKey; +use bitcoin::hashes::Hash; use bitcoin::secp256k1::PublicKey; -use bitcoin::util::bip32::ExtendedPrivKey; -use bitcoin::Network; +use bitcoin::{hashes::sha256, Network}; use fedimint_core::{api::InviteCode, config::FederationId}; use futures::{pin_mut, select, FutureExt}; +use hex_conservative::{DisplayHex, FromHex}; #[cfg(target_arch = "wasm32")] use instant::Instant; use lightning::ln::PaymentHash; @@ -294,10 +294,11 @@ impl From for MutinyInvoice { fn from(value: Bolt11Invoice) -> Self { let description = match value.description() { Bolt11InvoiceDescription::Direct(a) => { - if a.is_empty() { + let desc = a.clone().into_inner(); + if desc.0.is_empty() { None } else { - Some(a.to_string()) + Some(desc.0) } } Bolt11InvoiceDescription::Hash(_) => None, @@ -329,14 +330,9 @@ impl From for MutinyInvoice { impl From for PaymentInfo { fn from(invoice: MutinyInvoice) -> Self { - let preimage = invoice + let preimage: Option<[u8; 32]> = invoice .preimage - .map(|s| hex::decode(s).expect("preimage should decode")) - .map(|v| { - let mut arr = [0; 32]; - arr[..].copy_from_slice(&v); - arr - }); + .map(|s| FromHex::from_hex(&s).expect("preimage should decode")); let secret = None; let status = invoice.status; let amt_msat = invoice @@ -387,7 +383,7 @@ impl MutinyInvoice { labels, amount_sats, payee_pubkey: i.payee_pubkey, - preimage: i.preimage.map(|p| p.to_hex()), + preimage: i.preimage.map(|p| p.to_lower_hex_string()), fees_paid: i.fee_paid_msat.map(|f| f / 1_000), ..invoice.into() }) @@ -395,8 +391,8 @@ impl MutinyInvoice { None => { let amount_sats: Option = i.amt_msat.0.map(|s| s / 1_000); let fees_paid = i.fee_paid_msat.map(|f| f / 1_000); - let preimage = i.preimage.map(|p| p.to_hex()); - let payment_hash = sha256::Hash::from_inner(payment_hash.0); + let preimage = i.preimage.map(|p| p.to_lower_hex_string()); + let payment_hash = sha256::Hash::from_byte_array(payment_hash.0); let invoice = MutinyInvoice { bolt11: None, description: None, @@ -816,25 +812,6 @@ impl MutinyWalletBuilder { safe_mode: self.safe_mode, }; - #[cfg(not(test))] - { - // if we need a full sync from a restore - if mw.storage.get(NEED_FULL_SYNC_KEY)?.unwrap_or_default() { - let start = Instant::now(); - log_info!(mw.logger, "Full sync needed from restore"); - mw.node_manager - .wallet - .full_sync(crate::onchain::RESTORE_SYNC_STOP_GAP) - .await?; - mw.storage.delete(&[NEED_FULL_SYNC_KEY])?; - log_info!( - mw.logger, - "Full sync complete, took: {}ms", - start.elapsed().as_millis() - ); - } - } - // if we are in safe mode, don't create any nodes or // start any nostr services if self.safe_mode { @@ -1048,7 +1025,7 @@ impl MutinyWallet { labels: Vec, ) -> Result { if inv.network() != self.network { - return Err(MutinyError::IncorrectNetwork(inv.network())); + return Err(MutinyError::IncorrectNetwork); } // check invoice is expired @@ -1698,7 +1675,7 @@ impl MutinyWallet { .iter() .filter_map(|(_, c)| { if c.npub.is_some_and(|n| metadata.get(&n).is_none()) { - c.npub.map(|n| n.to_hex()) + c.npub.map(|n| n.serialize().to_lower_hex_string()) } else { None } @@ -1768,18 +1745,20 @@ impl MutinyWallet { let client = reqwest::Client::new(); // api is a little weird, has sender and receiver but still gives full conversation + let sender = npub.serialize().to_lower_hex_string(); + let receiver = self.nostr.public_key.serialize().to_lower_hex_string(); let body = match (until, since) { (Some(until), Some(since)) => { - json!(["get_directmsgs", { "sender": npub.to_hex(), "receiver": self.nostr.public_key.to_hex(), "limit": limit, "until": until, "since": since }]) + json!(["get_directmsgs", { "sender": sender, "receiver": receiver, "limit": limit, "until": until, "since": since }]) } (None, Some(since)) => { - json!(["get_directmsgs", { "sender": npub.to_hex(), "receiver": self.nostr.public_key.to_hex(), "limit": limit, "since": since }]) + json!(["get_directmsgs", { "sender": sender, "receiver": receiver, "limit": limit, "since": since }]) } (Some(until), None) => { - json!(["get_directmsgs", { "sender": npub.to_hex(), "receiver": self.nostr.public_key.to_hex(), "limit": limit, "until": until }]) + json!(["get_directmsgs", { "sender": sender, "receiver": receiver, "limit": limit, "until": until }]) } (None, None) => { - json!(["get_directmsgs", { "sender": npub.to_hex(), "receiver": self.nostr.public_key.to_hex(), "limit": limit, "since": 0 }]) + json!(["get_directmsgs", { "sender": sender, "receiver": receiver, "limit": limit, "since": 0 }]) } }; let data: Vec = Self::primal_request(&client, url, body).await?; @@ -1916,7 +1895,7 @@ impl MutinyWallet { network: Option, ) -> Result { if invoice.network() != network.unwrap_or(self.network) { - return Err(MutinyError::IncorrectNetwork(invoice.network())); + return Err(MutinyError::IncorrectNetwork); } Ok(invoice.into()) @@ -2242,7 +2221,7 @@ impl InvoiceHandler for MutinyWallet { } async fn get_outbound_payment_status(&self, payment_hash: &[u8; 32]) -> Option { - self.get_invoice_by_hash(&sha256::Hash::from_inner(*payment_hash)) + self.get_invoice_by_hash(&sha256::Hash::from_byte_array(*payment_hash)) .await .ok() .map(|p| p.status) @@ -2533,7 +2512,7 @@ mod tests { encrypt::encryption_key_from_pass, generate_seed, max_routing_fee_amount, nodemanager::NodeManager, MutinyWallet, MutinyWalletBuilder, MutinyWalletConfigBuilder, }; - use bitcoin::util::bip32::ExtendedPrivKey; + use bitcoin::bip32::ExtendedPrivKey; use bitcoin::Network; use crate::test_utils::*; @@ -2659,7 +2638,7 @@ mod tests { .await .expect("mutiny wallet should initialize"); let seed = mw.node_manager.xprivkey; - assert!(!seed.private_key.is_empty()); + assert!(!seed.private_key.secret_bytes().is_empty()); // create a second mw and make sure it has a different seed let pass = uuid::Uuid::new_v4().to_string(); diff --git a/mutiny-core/src/lnurlauth.rs b/mutiny-core/src/lnurlauth.rs index 7a89e04fa..5dd31f8c4 100644 --- a/mutiny-core/src/lnurlauth.rs +++ b/mutiny-core/src/lnurlauth.rs @@ -1,9 +1,9 @@ use crate::{error::MutinyError, logging::MutinyLogger}; use anyhow::anyhow; use bdk_chain::collections::HashMap; +use bitcoin::bip32::{DerivationPath, ExtendedPrivKey}; use bitcoin::hashes::hex::FromHex; use bitcoin::secp256k1::{ecdsa, All, Message, PublicKey, Secp256k1, SecretKey}; -use bitcoin::util::bip32::{DerivationPath, ExtendedPrivKey}; use lightning::util::logger::*; use lightning::{log_error, log_info}; use lnurl::lnurl::LnUrl; diff --git a/mutiny-core/src/logging.rs b/mutiny-core/src/logging.rs index 1dbdfa73d..e00c0ab79 100644 --- a/mutiny-core/src/logging.rs +++ b/mutiny-core/src/logging.rs @@ -1,4 +1,3 @@ -use bitcoin::hashes::hex::ToHex; use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, @@ -8,6 +7,7 @@ use crate::storage::MutinyStorage; use crate::utils::Mutex; use crate::{error::MutinyError, utils, utils::sleep}; use chrono::Utc; +use hex_conservative::DisplayHex; use lightning::util::logger::{Level, Logger, Record}; use log::*; @@ -99,11 +99,11 @@ impl Default for MutinyLogger { fn gen_session_id() -> String { let mut entropy = vec![0u8; 2]; getrandom::getrandom(&mut entropy).unwrap(); - entropy.to_hex() + entropy.to_lower_hex_string() } impl Logger for MutinyLogger { - fn log(&self, record: &Record) { + fn log(&self, record: Record) { let raw_log = record.args.to_string(); let log = format!( "{} {} {:<5} [{}:{}] {}\n", @@ -172,7 +172,7 @@ pub struct TestLogger {} #[cfg(test)] impl Logger for TestLogger { - fn log(&self, record: &Record) { + fn log(&self, record: Record) { let raw_log = record.args.to_string(); let log = format!( "{} {:<5} [{}:{}] {}\n", diff --git a/mutiny-core/src/lsp/lsps.rs b/mutiny-core/src/lsp/lsps.rs index 5d3622a1e..ca84f1ab9 100644 --- a/mutiny-core/src/lsp/lsps.rs +++ b/mutiny-core/src/lsp/lsps.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use bitcoin::hashes::{sha256, Hash}; -use bitcoin::secp256k1::{PublicKey, Secp256k1}; +use bitcoin::secp256k1::{PublicKey, Secp256k1, ThirtyTwoByteHash}; use bitcoin::Network; use futures::channel::oneshot; use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA; @@ -45,8 +45,11 @@ pub(crate) struct JitChannelInfo { #[derive(Clone, Debug)] pub(crate) struct GetInfoResponse { - pub jit_channel_id: u128, pub opening_fee_params_menu: Vec, + /// The min payment size allowed when opening the channel. + pub min_payment_size_msat: u64, + /// The max payment size allowed when opening the channel. + pub max_payment_size_msat: u64, } pub(crate) struct PendingPaymentInfo { @@ -67,7 +70,7 @@ pub struct LspsClient { keys_manager: Arc>, network: Network, logger: Arc, - pending_fee_requests: Arc>>, + pending_fee_requests: Arc>>, pending_buy_requests: Arc>>, pending_channel_info: Arc>>, pending_payments: Arc>>, @@ -114,26 +117,27 @@ impl LspsClient { pub(crate) async fn handle_event(&self, event: Event) { match event { - Event::LSPS2Client(LSPS2ClientEvent::GetInfoResponse { - jit_channel_id, + Event::LSPS2Client(LSPS2ClientEvent::OpeningParametersReady { + counterparty_node_id, opening_fee_params_menu, - user_channel_id, - .. + min_payment_size_msat, + max_payment_size_msat, }) => { log_debug!( self.logger, - "received GetInfoResponse for jit_channel_id {}, user_channel_id {}", - jit_channel_id, - user_channel_id + "received GetInfoResponse for counterparty_node_id {counterparty_node_id}", ); let mut pending_fee_requests = self.pending_fee_requests.lock().unwrap(); - if let Some(fee_response_sender) = pending_fee_requests.remove(&user_channel_id) { + if let Some(fee_response_sender) = + pending_fee_requests.remove(&counterparty_node_id) + { if fee_response_sender .send(Ok(GetInfoResponse { - jit_channel_id, opening_fee_params_menu, + min_payment_size_msat, + max_payment_size_msat, })) .is_err() { @@ -141,7 +145,7 @@ impl LspsClient { } } } - Event::LSPS2Client(LSPS2ClientEvent::InvoiceGenerationReady { + Event::LSPS2Client(LSPS2ClientEvent::InvoiceParametersReady { intercept_scid, cltv_expiry_delta, user_channel_id, @@ -361,7 +365,7 @@ impl Lsp for LspsClient { { let mut pending_fee_requests = self.pending_fee_requests.lock().unwrap(); - pending_fee_requests.insert(user_channel_id, pending_fee_request_sender); + pending_fee_requests.insert(self.pubkey, pending_fee_request_sender); } log_debug!( @@ -376,12 +380,7 @@ impl Lsp for LspsClient { .lsps2_client_handler() .expect("to be configured with lsps2 client config"); - lsps2_client_handler.create_invoice( - self.pubkey, - Some(fee_request.amount_msat), - self.token.clone(), - user_channel_id, - ); + lsps2_client_handler.request_opening_params(self.pubkey, self.token.clone()); let get_info_response = pending_fee_request_receiver.await.map_err(|e| { log_debug!(self.logger, "error receiving get info response: {:?}", e); @@ -395,9 +394,11 @@ impl Lsp for LspsClient { log_debug!( self.logger, - "received fee information. min_fee_msat {} and proportional fee {}", + "received fee information. min_fee_msat {}, proportional fee {}, min payment {}msats, max payment {}msats", min_fee_msat, - proportional_fee + proportional_fee, + get_info_response.min_payment_size_msat, + get_info_response.max_payment_size_msat, ); { @@ -405,7 +406,7 @@ impl Lsp for LspsClient { pending_channel_info.insert( user_channel_id, JitChannelInfo { - channel_id: get_info_response.jit_channel_id, + channel_id: user_channel_id, fee_params, }, ); @@ -455,14 +456,14 @@ impl Lsp for LspsClient { .expect("to be configured with lsps2 client config"); lsps2_client_handler - .opening_fee_params_selected(self.pubkey, channel_id, fee_params.clone()) + .select_opening_params(self.pubkey, channel_id, None, fee_params.clone()) .map_err(|_| MutinyError::LspGenericError)?; let invoice = pending_buy_request_receiver .await .map_err(|_| MutinyError::LspGenericError)??; - let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner()); + let payment_hash = PaymentHash(invoice.payment_hash().into_32()); let payment_amount = invoice.amount_milli_satoshis(); let expected_fee_msat = payment_amount.and_then(|payment_amount| { diff --git a/mutiny-core/src/node.rs b/mutiny-core/src/node.rs index a030e43d2..32c11c624 100644 --- a/mutiny-core/src/node.rs +++ b/mutiny-core/src/node.rs @@ -29,18 +29,20 @@ use crate::{ use crate::{messagehandler::MutinyMessageHandler, storage::read_payment_info}; use anyhow::{anyhow, Context}; use bdk::FeeRate; -use bitcoin::hashes::{hex::ToHex, sha256::Hash as Sha256}; -use bitcoin::util::bip32::ExtendedPrivKey; +use bitcoin::bip32::ExtendedPrivKey; +use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::secp256k1::ThirtyTwoByteHash; use bitcoin::{hashes::Hash, secp256k1::PublicKey, Network, OutPoint}; use core::time::Duration; use esplora_client::AsyncClient; use futures_util::lock::Mutex; +use hex_conservative::DisplayHex; #[cfg(target_arch = "wasm32")] use instant::Instant; use lightning::events::bump_transaction::{BumpTransactionEventHandler, Wallet}; use lightning::ln::channelmanager::ChannelDetails; use lightning::ln::PaymentSecret; -use lightning::onion_message::OnionMessenger as LdkOnionMessenger; +use lightning::onion_message::messenger::OnionMessenger as LdkOnionMessenger; use lightning::routing::scoring::ProbabilisticScoringDecayParameters; use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient}; use lightning::util::config::MaxDustHTLCExposure; @@ -69,7 +71,6 @@ use lightning::{ util::config::ChannelConfig, }; use lightning_background_processor::process_events_async; -use lightning_invoice::payment::PaymentError; use lightning_invoice::{ utils::{create_invoice_from_channelmanager_and_duration_since_epoch, create_phantom_invoice}, Bolt11Invoice, @@ -447,7 +448,7 @@ impl NodeBuilder { None, None, Some(LiquidityClientConfig { - lsps2_client_config: Some(LSPS2ClientConfig {}), + lsps2_client_config: Some(LSPS2ClientConfig::default()), }), )); let lsp = AnyLsp::new_lsps( @@ -531,7 +532,7 @@ impl NodeBuilder { Vec::with_capacity(read_channel_manager.channel_monitors.len()); for (blockhash, channel_monitor) in read_channel_manager.channel_monitors.drain(..) { // Get channel monitor ready to sync - channel_monitor.load_outputs_to_watch(&chain); + channel_monitor.load_outputs_to_watch(&chain, &logger); let outpoint = channel_monitor.get_funding_txo().0; chain_listener_channel_monitors.push(( @@ -650,14 +651,14 @@ impl NodeBuilder { log_debug!( logger, "changed default config for channel: {}", - channel.channel_id.to_hex() + channel.channel_id ) } Err(e) => { log_error!( logger, "error changing default config for channel: {} - {e:?}", - channel.channel_id.to_hex() + channel.channel_id ) } }; @@ -698,6 +699,7 @@ impl NodeBuilder { }) }, true, + || Some(utils::now()), ) .await { @@ -708,13 +710,13 @@ impl NodeBuilder { log_debug!( background_logger, "stopping background component for node: {}", - pubkey.to_hex(), + pubkey, ); stop_component(&background_stopped_components); log_debug!( background_logger, "stopped background component for node: {}", - pubkey.to_hex() + pubkey ); break; } @@ -1047,7 +1049,7 @@ impl Node { // check the fee from the LSP let lsp_fee = lsp .get_lsp_fee_msat(FeeRequest { - pubkey: self.pubkey.to_hex(), + pubkey: self.pubkey.encode().to_lower_hex_string(), amount_msat: amount_sat * 1000, user_channel_id, }) @@ -1104,7 +1106,7 @@ impl Node { // check the fee from the LSP let lsp_fee = lsp .get_lsp_fee_msat(FeeRequest { - pubkey: self.pubkey.to_hex(), + pubkey: self.pubkey.encode().to_lower_hex_string(), amount_msat: amount_sat * 1000, user_channel_id, }) @@ -1146,7 +1148,7 @@ impl Node { .await?; if invoice.network() != self.network { - return Err(MutinyError::IncorrectNetwork(invoice.network())); + return Err(MutinyError::IncorrectNetwork); } if lsp_invoice.payment_hash() != invoice.payment_hash() @@ -1292,7 +1294,7 @@ impl Node { labels: Vec, ) -> Result<(), MutinyError> { let last_update = utils::now().as_secs(); - let payment_hash = PaymentHash(invoice.payment_hash().into_inner()); + let payment_hash = PaymentHash(invoice.payment_hash().into_32()); let payment_info = PaymentInfo { preimage: None, secret: Some(invoice.payment_secret().0), @@ -1330,7 +1332,7 @@ impl Node { MutinyInvoice::from( payment_info, - PaymentHash(payment_hash.into_inner()), + PaymentHash(payment_hash.into_32()), inbound, labels, ) @@ -1368,7 +1370,7 @@ impl Node { // try inbound first if let Some(payment_info) = read_payment_info( &self.persister.storage, - payment_hash.as_inner(), + &payment_hash.into_32(), true, &self.logger, ) { @@ -1378,7 +1380,7 @@ impl Node { // if no inbound check outbound match read_payment_info( &self.persister.storage, - payment_hash.as_inner(), + &payment_hash.into_32(), false, &self.logger, ) { @@ -1398,15 +1400,15 @@ impl Node { invoice: &Bolt11Invoice, amt_sats: Option, ) -> Result<(PaymentId, PaymentHash), MutinyError> { - let payment_hash = invoice.payment_hash().as_inner(); + let payment_hash = invoice.payment_hash().into_32(); - if read_payment_info(&self.persister.storage, payment_hash, false, &self.logger) + if read_payment_info(&self.persister.storage, &payment_hash, false, &self.logger) .is_some_and(|p| p.status != HTLCStatus::Failed) { return Err(MutinyError::NonUniquePaymentHash); } - if read_payment_info(&self.persister.storage, payment_hash, true, &self.logger) + if read_payment_info(&self.persister.storage, &payment_hash, true, &self.logger) .is_some_and(|p| p.status != HTLCStatus::Failed) { return Err(MutinyError::NonUniquePaymentHash); @@ -1477,10 +1479,10 @@ impl Node { last_update, }; - persist_payment_info(&self.persister.storage, payment_hash, &payment_info, false)?; + persist_payment_info(&self.persister.storage, &payment_hash, &payment_info, false)?; match pay_result { - Ok(id) => Ok((id, PaymentHash(payment_hash.to_owned()))), + Ok(id) => Ok((id, PaymentHash(payment_hash))), Err(error) => { log_error!(self.logger, "failed to make payment: {error:?}"); // call list channels to see what our channels are @@ -1492,7 +1494,7 @@ impl Node { ); payment_info.status = HTLCStatus::Failed; - persist_payment_info(&self.persister.storage, payment_hash, &payment_info, false)?; + persist_payment_info(&self.persister.storage, &payment_hash, &payment_info, false)?; Err(map_sending_failure(error, amt_msat, ¤t_channels)) } @@ -1504,9 +1506,9 @@ impl Node { &self, invoice: &Bolt11Invoice, amount_msats: u64, - ) -> Result { - let payment_id = PaymentId(invoice.payment_hash().into_inner()); - let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner()); + ) -> Result { + let payment_id = PaymentId(invoice.payment_hash().into_32()); + let payment_hash = PaymentHash((*invoice.payment_hash()).into_32()); let mut recipient_onion = RecipientOnionFields::secret_only(*invoice.payment_secret()); recipient_onion.payment_metadata = invoice.payment_metadata().cloned(); let mut payment_params = PaymentParameters::from_node_id( @@ -1527,16 +1529,16 @@ impl Node { max_total_routing_fee_msat: None, // main change from LDK, we just want payment to succeed }; - match self.channel_manager.as_ref().send_payment( - payment_hash, - recipient_onion, - payment_id, - route_params, - Self::retry_strategy(), - ) { - Ok(()) => Ok(payment_id), - Err(e) => Err(PaymentError::Sending(e)), - } + self.channel_manager + .as_ref() + .send_payment( + payment_hash, + recipient_onion, + payment_id, + route_params, + Self::retry_strategy(), + ) + .map(|_| payment_id) } async fn await_payment( @@ -1641,7 +1643,7 @@ impl Node { Self::retry_strategy(), ); - let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner()); + let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_32()); let last_update = utils::now().as_secs(); let mut payment_info = PaymentInfo { @@ -1677,11 +1679,7 @@ impl Node { false, )?; let current_channels = self.channel_manager.list_channels(); - Err(map_sending_failure( - PaymentError::Sending(error), - amt_msats, - ¤t_channels, - )) + Err(map_sending_failure(error, amt_msats, ¤t_channels)) } } } @@ -1703,7 +1701,7 @@ impl Node { self.init_keysend_payment(to_node, amt_sats, message, labels.clone(), payment_id)?; let timeout: u64 = timeout_secs.unwrap_or(DEFAULT_PAYMENT_TIMEOUT); - let payment_hash = PaymentHash(pay.payment_hash.into_inner()); + let payment_hash = PaymentHash(pay.payment_hash.into_32()); self.await_payment(payment_id, payment_hash, timeout, labels) .await @@ -1816,6 +1814,7 @@ impl Node { amount_sat, 0, user_channel_id, + None, Some(config), ) { Ok(_) => { @@ -1916,6 +1915,7 @@ impl Node { channel_value_satoshis, 0, user_channel_id, + None, Some(config), ) { Ok(_) => { @@ -1972,14 +1972,14 @@ pub(crate) fn decay_params() -> ProbabilisticScoringDecayParameters { } fn map_sending_failure( - error: PaymentError, + error: RetryableSendFailure, amt_msat: u64, current_channels: &[ChannelDetails], ) -> MutinyError { // If the payment failed because of a route not found, check if the amount was // valid and return the correct error match error { - PaymentError::Sending(RetryableSendFailure::RouteNotFound) => { + RetryableSendFailure::RouteNotFound => { // If the amount was greater than our balance, return an InsufficientBalance error let ln_balance: u64 = current_channels.iter().map(|c| c.balance_msat).sum(); if amt_msat > ln_balance { @@ -2007,11 +2007,8 @@ fn map_sending_failure( MutinyError::RoutingFailed } - PaymentError::Invoice(_) => MutinyError::InvoiceInvalid, - PaymentError::Sending(RetryableSendFailure::PaymentExpired) => MutinyError::InvoiceInvalid, - PaymentError::Sending(RetryableSendFailure::DuplicatePayment) => { - MutinyError::NonUniquePaymentHash - } + RetryableSendFailure::PaymentExpired => MutinyError::InvoiceExpired, + RetryableSendFailure::DuplicatePayment => MutinyError::NonUniquePaymentHash, } } @@ -2194,14 +2191,14 @@ async fn start_reconnection_handling( log_debug!( proxy_logger, "stopping connection component and disconnecting peers for node: {}", - node_pubkey.to_hex(), + node_pubkey, ); peer_man_proxy.disconnect_all_peers(); stop_component(&stopped_components); log_debug!( proxy_logger, "stopped connection component and disconnected peers for node: {}", - node_pubkey.to_hex(), + node_pubkey, ); return; } @@ -2214,14 +2211,14 @@ async fn start_reconnection_handling( log_debug!( proxy_logger, "stopping connection component and disconnecting peers for node: {}", - node_pubkey.to_hex(), + node_pubkey, ); peer_man_proxy.disconnect_all_peers(); stop_component(&stopped_components); log_debug!( proxy_logger, "stopped connection component and disconnected peers for node: {}", - node_pubkey.to_hex(), + node_pubkey, ); return; } @@ -2438,23 +2435,11 @@ mod tests { // test simple cases assert_eq!( - map_sending_failure(PaymentError::Invoice(""), amt_msat, &[]), - MutinyError::InvoiceInvalid - ); - assert_eq!( - map_sending_failure( - PaymentError::Sending(RetryableSendFailure::PaymentExpired), - amt_msat, - &[] - ), - MutinyError::InvoiceInvalid + map_sending_failure(RetryableSendFailure::PaymentExpired, amt_msat, &[]), + MutinyError::InvoiceExpired ); assert_eq!( - map_sending_failure( - PaymentError::Sending(RetryableSendFailure::DuplicatePayment), - amt_msat, - &[] - ), + map_sending_failure(RetryableSendFailure::DuplicatePayment, amt_msat, &[]), MutinyError::NonUniquePaymentHash ); @@ -2497,7 +2482,7 @@ mod tests { assert_eq!( map_sending_failure( - PaymentError::Sending(RetryableSendFailure::RouteNotFound), + RetryableSendFailure::RouteNotFound, amt_msat, &[channel_details.clone()] ), @@ -2506,7 +2491,7 @@ mod tests { assert_eq!( map_sending_failure( - PaymentError::Sending(RetryableSendFailure::RouteNotFound), + RetryableSendFailure::RouteNotFound, amt_msat, &[channel_details.clone()] ), @@ -2518,7 +2503,7 @@ mod tests { channel_details.unspendable_punishment_reserve = Some(20); assert_eq!( map_sending_failure( - PaymentError::Sending(RetryableSendFailure::RouteNotFound), + RetryableSendFailure::RouteNotFound, amt_msat, &[channel_details.clone()] ), @@ -2529,7 +2514,7 @@ mod tests { channel_details.unspendable_punishment_reserve = Some(0); assert_eq!( map_sending_failure( - PaymentError::Sending(RetryableSendFailure::RouteNotFound), + RetryableSendFailure::RouteNotFound, amt_msat, &[channel_details.clone()] ), @@ -2540,7 +2525,7 @@ mod tests { channel_details.next_outbound_htlc_limit_msat = amt_msat + 10; assert_eq!( map_sending_failure( - PaymentError::Sending(RetryableSendFailure::RouteNotFound), + RetryableSendFailure::RouteNotFound, amt_msat, &[channel_details.clone()] ), @@ -2552,7 +2537,7 @@ mod tests { async fn test_create_node() { let storage = MemoryStorage::default(); let node = create_node(storage).await; - assert!(!node.pubkey.to_hex().is_empty()); + assert!(!node.pubkey.to_string().is_empty()); } #[tokio::test] @@ -2698,7 +2683,6 @@ mod wasm_test { use crate::test_utils::create_node; use crate::HTLCStatus; use crate::{error::MutinyError, storage::persist_payment_info}; - use bitcoin::hashes::hex::ToHex; use lightning::ln::channelmanager::PaymentId; use lightning::ln::PaymentHash; use lightning_invoice::Bolt11InvoiceDescription; @@ -2710,7 +2694,7 @@ mod wasm_test { async fn test_create_node() { let storage = MemoryStorage::default(); let node = create_node(storage).await; - assert!(!node.pubkey.to_hex().is_empty()); + assert!(!node.pubkey.to_string().is_empty()); } #[test] diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index 44d9d27b7..b451dc7c5 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -27,17 +27,18 @@ use crate::{ use anyhow::anyhow; use async_lock::RwLock; use bdk::chain::{BlockId, ConfirmationTime}; -use bdk::{wallet::AddressIndex, FeeRate, LocalUtxo}; +use bdk::{wallet::AddressIndex, FeeRate, LocalOutput}; +use bitcoin::address::NetworkUnchecked; +use bitcoin::bip32::ExtendedPrivKey; use bitcoin::blockdata::script; -use bitcoin::hashes::hex::ToHex; use bitcoin::hashes::sha256; use bitcoin::psbt::PartiallySignedTransaction; use bitcoin::secp256k1::PublicKey; -use bitcoin::util::bip32::ExtendedPrivKey; use bitcoin::{Address, Network, OutPoint, Transaction, Txid}; use core::time::Duration; use esplora_client::{AsyncClient, Builder}; use futures::{future::join_all, lock::Mutex}; +use hex_conservative::DisplayHex; #[cfg(target_arch = "wasm32")] use instant::Instant; use lightning::chain::Confirm; @@ -97,7 +98,7 @@ pub struct NodeIdentity { pub pubkey: PublicKey, } -#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Serialize, Clone, Eq, PartialEq)] pub struct MutinyBip21RawMaterials { pub address: Address, pub invoice: Option, @@ -149,7 +150,7 @@ pub struct MutinyChannel { impl From<&ChannelDetails> for MutinyChannel { fn from(c: &ChannelDetails) -> Self { MutinyChannel { - user_chan_id: c.user_channel_id.to_hex(), + user_chan_id: c.user_channel_id.to_be_bytes().to_lower_hex_string(), balance: c.next_outbound_htlc_limit_msat / 1_000, size: c.channel_value_satoshis, reserve: ((c.outbound_capacity_msat - c.next_outbound_htlc_limit_msat) / 1_000) @@ -214,20 +215,6 @@ impl Ord for TransactionDetails { } } -impl From for TransactionDetails { - fn from(t: bdk::TransactionDetails) -> Self { - TransactionDetails { - transaction: t.transaction, - txid: t.txid, - received: t.received, - sent: t.sent, - fee: t.fee, - confirmation_time: t.confirmation_time, - labels: vec![], - } - } -} - /// Information about a channel that was closed. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] pub struct ChannelClosure { @@ -365,7 +352,6 @@ impl NodeManagerBuilder { let esplora = Arc::new(esplora); let fee_estimator = Arc::new(MutinyFeeEstimator::new( self.storage.clone(), - c.network, esplora.clone(), logger.clone(), )); @@ -591,14 +577,10 @@ impl NodeManager { let node_futures = nodes.iter().map(|(_, n)| async { match n.stop().await { Ok(_) => { - log_debug!(self.logger, "stopped node: {}", n.pubkey.to_hex()) + log_debug!(self.logger, "stopped node: {}", n.pubkey) } Err(e) => { - log_error!( - self.logger, - "failed to stop node {}: {e}", - n.pubkey.to_hex() - ) + log_error!(self.logger, "failed to stop node {}: {e}", n.pubkey) } } }); @@ -684,7 +666,7 @@ impl NodeManager { /// Will generate the last unused address in our bdk wallet. pub fn get_new_address(&self, labels: Vec) -> Result { if let Ok(mut wallet) = self.wallet.wallet.try_write() { - let address = wallet.get_address(AddressIndex::LastUnused).address; + let address = wallet.try_get_address(AddressIndex::LastUnused)?.address; self.set_address_labels(address.clone(), labels)?; return Ok(address); } @@ -708,13 +690,15 @@ impl NodeManager { pub async fn send_payjoin( &self, - uri: Uri<'_, payjoin::bitcoin::address::NetworkChecked>, + uri: Uri<'_, NetworkUnchecked>, amount: u64, labels: Vec, fee_rate: Option, ) -> Result { - let address = Address::from_str(&uri.address.to_string()) - .map_err(|_| MutinyError::InvalidArgumentsError)?; + let uri = uri + .require_network(self.network) + .map_err(|_| MutinyError::IncorrectNetwork)?; + let address = uri.address.clone(); let original_psbt = self.wallet.create_signed_psbt(address, amount, fee_rate)?; let fee_rate = if let Some(rate) = fee_rate { @@ -784,16 +768,14 @@ impl NodeManager { /// If a fee rate is not provided, one will be used from the fee estimator. pub async fn send_to_address( &self, - send_to: Address, + send_to: Address, amount: u64, labels: Vec, fee_rate: Option, ) -> Result { - if !send_to.is_valid_for_network(self.network) { - return Err(MutinyError::IncorrectNetwork(send_to.network)); - } + let address = send_to.require_network(self.network)?; - self.wallet.send(send_to, amount, labels, fee_rate).await + self.wallet.send(address, amount, labels, fee_rate).await } /// Sweeps all the funds from the wallet to the given address. @@ -802,15 +784,13 @@ impl NodeManager { /// If a fee rate is not provided, one will be used from the fee estimator. pub async fn sweep_wallet( &self, - send_to: Address, + send_to: Address, labels: Vec, fee_rate: Option, ) -> Result { - if !send_to.is_valid_for_network(self.network) { - return Err(MutinyError::IncorrectNetwork(send_to.network)); - } + let address = send_to.require_network(self.network)?; - self.wallet.sweep(send_to, labels, fee_rate).await + self.wallet.sweep(address, labels, fee_rate).await } /// Estimates the onchain fee for a transaction sending to the given address. @@ -848,7 +828,7 @@ impl NodeManager { // Dummy p2wsh script for the channel output let script = script::Builder::new() .push_int(0) - .push_slice(&[0; 32]) + .push_slice([0; 32]) .into_script(); self.wallet.estimate_tx_fee(script, amount, fee_rate) } @@ -862,7 +842,7 @@ impl NodeManager { // Dummy p2wsh script for the channel output let script = script::Builder::new() .push_int(0) - .push_slice(&[0; 32]) + .push_slice([0; 32]) .into_script(); self.wallet.estimate_sweep_tx_fee(script, fee_rate) } @@ -889,11 +869,9 @@ impl NodeManager { /// This should be used to check if a payment has been made to an address. pub async fn check_address( &self, - address: &Address, + address: Address, ) -> Result, MutinyError> { - if !address.is_valid_for_network(self.network) { - return Err(MutinyError::IncorrectNetwork(address.network)); - } + let address = address.require_network(self.network)?; let script = address.payload.script_pubkey(); let txs = self.esplora.scripthash_txs(&script, None).await?; @@ -1032,10 +1010,10 @@ impl NodeManager { fn add_onchain_labels( &self, address_labels: &HashMap>, - tx: bdk::TransactionDetails, + mut tx: TransactionDetails, ) -> TransactionDetails { // find the first output address that has a label - let labels = tx + tx.labels = tx .transaction .clone() .unwrap() // safe because we call with list_transactions(true) @@ -1050,10 +1028,7 @@ impl NodeManager { }) .unwrap_or_default(); - TransactionDetails { - labels, - ..tx.into() - } + tx } /// Lists all the on-chain transactions in the wallet. @@ -1072,7 +1047,7 @@ impl NodeManager { /// Gets the details of a specific on-chain transaction. pub fn get_transaction(&self, txid: Txid) -> Result, MutinyError> { - match self.wallet.get_transaction(txid, true)? { + match self.wallet.get_transaction(txid)? { Some(tx) => { let address_labels = self.get_address_labels()?; let tx_details = self.add_onchain_labels(&address_labels, tx); @@ -1130,7 +1105,7 @@ impl NodeManager { } /// Lists all the UTXOs in the wallet. - pub fn list_utxos(&self) -> Result, MutinyError> { + pub fn list_utxos(&self) -> Result, MutinyError> { self.wallet.list_utxos() } @@ -1700,8 +1675,8 @@ impl NodeManager { log_error!( self.logger, "had an error force closing channel {} with node {} : {e:?}", - &channel.channel_id.to_hex(), - &channel.counterparty.node_id.to_hex() + &channel.channel_id, + &channel.counterparty.node_id ); MutinyError::ChannelClosingFailed })?; @@ -1715,8 +1690,8 @@ impl NodeManager { log_error!( self.logger, "had an error abandoning closing channel {} with node {} : {e:?}", - &channel.channel_id.to_hex(), - &channel.counterparty.node_id.to_hex() + &channel.channel_id, + &channel.counterparty.node_id ); MutinyError::ChannelClosingFailed })?; @@ -1743,8 +1718,8 @@ impl NodeManager { log_error!( self.logger, "had an error closing channel {} with node {} : {e:?}", - &channel.channel_id.to_hex(), - &channel.counterparty.node_id.to_hex() + &channel.channel_id, + &channel.counterparty.node_id ); MutinyError::ChannelClosingFailed })?; @@ -2140,11 +2115,12 @@ mod tests { }; use crate::{keymanager::generate_seed, nodemanager::NodeManagerBuilder}; use bdk::chain::ConfirmationTime; - use bitcoin::hashes::hex::{FromHex, ToHex}; + use bitcoin::bip32::ExtendedPrivKey; + use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::{sha256, Hash}; - use bitcoin::secp256k1::PublicKey; - use bitcoin::util::bip32::ExtendedPrivKey; - use bitcoin::{Network, PackedLockTime, Transaction, TxOut, Txid}; + use bitcoin::secp256k1::{PublicKey, ThirtyTwoByteHash}; + use bitcoin::{absolute, Network, Transaction, TxOut, Txid}; + use hex_conservative::DisplayHex; use lightning::ln::PaymentHash; use lightning_invoice::Bolt11Invoice; use std::collections::HashMap; @@ -2259,7 +2235,7 @@ mod tests { let fake_tx = Transaction { version: 2, - lock_time: PackedLockTime::ZERO, + lock_time: absolute::LockTime::ZERO, input: vec![], output: vec![TxOut { value: 1_000_000, @@ -2304,7 +2280,7 @@ mod tests { FromHex::from_hex("7722126954f07b120ba373f2b529efc3ce3a279ab4785a912edfe783c2cdb60b") .unwrap(); - let payment_hash = sha256::Hash::from_hex( + let payment_hash = sha256::Hash::from_str( "55ecf9169a6fa07e8ba181fdddf5b0bcc7860176659fa22a7cca9da2a359a33b", ) .unwrap(); @@ -2328,7 +2304,7 @@ mod tests { bolt11: Some(invoice), description: None, payment_hash, - preimage: Some(preimage.to_hex()), + preimage: Some(preimage.to_lower_hex_string()), payee_pubkey: None, amount_sats: Some(100_000), expire: 1681781649 + 86400, @@ -2341,7 +2317,7 @@ mod tests { let actual = MutinyInvoice::from( payment_info, - PaymentHash(payment_hash.into_inner()), + PaymentHash(payment_hash.into_32()), true, labels, ) @@ -2356,7 +2332,7 @@ mod tests { FromHex::from_hex("7600f5a9ad72452dea7ad86dabbc9cb46be96a1a2fcd961e041d066b38d93008") .unwrap(); - let payment_hash = sha256::Hash::from_hex( + let payment_hash = sha256::Hash::from_str( "55ecf9169a6fa07e8ba181fdddf5b0bcc7860176659fa22a7cca9da2a359a33b", ) .unwrap(); @@ -2381,7 +2357,7 @@ mod tests { bolt11: None, description: None, payment_hash, - preimage: Some(preimage.to_hex()), + preimage: Some(preimage.to_lower_hex_string()), payee_pubkey: Some(pubkey), amount_sats: Some(100), expire: 1681781585, @@ -2394,7 +2370,7 @@ mod tests { let actual = MutinyInvoice::from( payment_info, - PaymentHash(payment_hash.into_inner()), + PaymentHash(payment_hash.into_32()), false, vec![], ) @@ -2434,7 +2410,7 @@ mod tests { FromHex::from_hex("7600f5a9ad72452dea7ad86dabbc9cb46be96a1a2fcd961e041d066b38d93008") .unwrap(); - let payment_hash = sha256::Hash::from_hex( + let payment_hash = sha256::Hash::from_str( "55ecf9169a6fa07e8ba181fdddf5b0bcc7860176659fa22a7cca9da2a359a33b", ) .unwrap(); @@ -2479,7 +2455,7 @@ mod tests { bolt11: None, description: None, payment_hash, - preimage: Some(preimage.to_hex()), + preimage: Some(preimage.to_lower_hex_string()), payee_pubkey: Some(pubkey), amount_sats: Some(100), expire: 1681781585, @@ -2494,7 +2470,7 @@ mod tests { bolt11: None, description: None, payment_hash, - preimage: Some(preimage.to_hex()), + preimage: Some(preimage.to_lower_hex_string()), payee_pubkey: Some(pubkey), amount_sats: Some(100), expire: 1681781585, @@ -2539,7 +2515,7 @@ mod tests { bolt11: None, description: Some("difference".to_string()), payment_hash, - preimage: Some(preimage.to_hex()), + preimage: Some(preimage.to_lower_hex_string()), payee_pubkey: Some(pubkey), amount_sats: Some(100), expire: 1681781585, diff --git a/mutiny-core/src/nostr/mod.rs b/mutiny-core/src/nostr/mod.rs index b907ea0ea..04b0034d5 100644 --- a/mutiny-core/src/nostr/mod.rs +++ b/mutiny-core/src/nostr/mod.rs @@ -9,13 +9,10 @@ use crate::storage::MutinyStorage; use crate::{error::MutinyError, utils::get_random_bip32_child_index}; use crate::{labels::LabelStorage, InvoiceHandler}; use crate::{utils, HTLCStatus}; +use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; use bitcoin::hashes::{sha256, Hash}; use bitcoin::secp256k1::{Secp256k1, Signing}; -use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; -use bitcoin::{ - hashes::hex::{FromHex, ToHex}, - secp256k1::ThirtyTwoByteHash, -}; +use bitcoin::{hashes::hex::FromHex, secp256k1::ThirtyTwoByteHash}; use futures::{pin_mut, select, FutureExt}; use futures_util::lock::Mutex; use lightning::util::logger::Logger; @@ -417,8 +414,7 @@ impl NostrManager { Some(identity) => { let contacts = self.storage.get_contacts()?; contacts.into_iter().find_map(|(id, c)| { - // compare by to_hex because of different types across rust-bitcoin versions - if c.npub.map(|x| x.to_hex()) == Some(identity.to_hex()) { + if c.npub == Some(identity) { Some(id) } else { None @@ -1285,7 +1281,7 @@ mod test { use crate::utils::now; use crate::MockInvoiceHandler; use bip39::Mnemonic; - use bitcoin::util::bip32::ExtendedPrivKey; + use bitcoin::bip32::ExtendedPrivKey; use bitcoin::Network; use futures::executor::block_on; use lightning::ln::PaymentSecret; diff --git a/mutiny-core/src/nostr/nwc.rs b/mutiny-core/src/nostr/nwc.rs index 5c748a774..9dc60c5fd 100644 --- a/mutiny-core/src/nostr/nwc.rs +++ b/mutiny-core/src/nostr/nwc.rs @@ -6,11 +6,12 @@ use crate::storage::MutinyStorage; use crate::utils; use crate::InvoiceHandler; use anyhow::anyhow; -use bitcoin::hashes::hex::{FromHex, ToHex}; +use bitcoin::bip32::ExtendedPrivKey; +use bitcoin::hashes::hex::FromHex; use bitcoin::secp256k1::{Secp256k1, Signing, ThirtyTwoByteHash}; -use bitcoin::util::bip32::ExtendedPrivKey; use chrono::{DateTime, Datelike, Duration, NaiveDateTime, Utc}; use core::fmt; +use hex_conservative::DisplayHex; use lightning::util::logger::Logger; use lightning::{log_error, log_warn}; use lightning_invoice::Bolt11Invoice; @@ -73,15 +74,15 @@ impl BudgetedSpendingConditions { let payment = TrackedPayment { time, amt: invoice.amount_milli_satoshis().unwrap_or_default() / 1_000, - hash: invoice.payment_hash().to_hex(), + hash: invoice.payment_hash().into_32().to_lower_hex_string(), }; self.payments.push(payment); } pub fn remove_payment(&mut self, invoice: &Bolt11Invoice) { - self.payments - .retain(|p| p.hash != invoice.payment_hash().to_hex()); + let hex = invoice.payment_hash().into_32().to_lower_hex_string(); + self.payments.retain(|p| p.hash != hex); } fn clean_old_payments(&mut self, now: DateTime) { @@ -302,7 +303,7 @@ impl NostrWalletConnect { &self.client_pubkey(), serde_json::to_string(&json)?, )?; - let d_tag = Tag::Identifier(self.client_pubkey().to_hex()); + let d_tag = Tag::Identifier(self.client_pubkey().serialize().to_lower_hex_string()); let event = EventBuilder::new(Kind::ParameterizedReplaceable(33194), content, [d_tag]) .to_event(&self.server_key)?; Ok(Some(event)) @@ -490,8 +491,12 @@ impl NostrWalletConnect { // if a payment times out, we should save the payment_hash // and track if the payment settles or not. If it does not // we can try again later. - single_use.payment_hash = - Some(invoice.payment_hash().to_hex()); + single_use.payment_hash = Some( + invoice + .payment_hash() + .into_32() + .to_lower_hex_string(), + ); self.profile.spending_conditions = SpendingConditions::SingleUse(single_use); needs_save = true; @@ -879,7 +884,7 @@ pub(crate) async fn check_valid_nwc_invoice( if invoice_handler.skip_hodl_invoices() { // Skip potential hodl invoices as they can cause force closes - if utils::HODL_INVOICE_NODES.contains(&invoice.recover_payee_pub_key().to_hex().as_str()) { + if utils::is_hodl_invoice(&invoice) { log_warn!( invoice_handler.logger(), "Received potential hodl invoice, skipping..." @@ -1181,7 +1186,6 @@ mod wasm_test { use crate::test_utils::{create_dummy_invoice, create_mutiny_wallet, create_nwc_request}; use crate::MockInvoiceHandler; use crate::MutinyInvoice; - use bitcoin::secp256k1::ONE_KEY; use bitcoin::Network; use mockall::predicate::eq; use nostr::key::SecretKey; @@ -1246,7 +1250,10 @@ mod wasm_test { let uri = nwc.get_nwc_uri().unwrap().unwrap(); // test hodl invoice - let invoice = create_dummy_invoice(Some(10_000), Network::Regtest, Some(ONE_KEY)) + let one = + SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); // one key + let invoice = create_dummy_invoice(Some(10_000), Network::Regtest, Some(one)) .0 .to_string(); let event = create_nwc_request(&uri, invoice.clone()); @@ -1406,7 +1413,10 @@ mod wasm_test { // test hodl invoice node.expect_skip_hodl_invoices().return_const(true); - let invoice = create_dummy_invoice(Some(10_000), Network::Regtest, Some(ONE_KEY)) + let one = + SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); // one key + let invoice = create_dummy_invoice(Some(10_000), Network::Regtest, Some(one)) .0 .to_string(); let event = create_nwc_request(&uri, invoice); @@ -1598,7 +1608,7 @@ mod wasm_test { .once() .returning(move |inv, _, _| { let mut mutiny_invoice: MutinyInvoice = inv.clone().into(); - mutiny_invoice.preimage = Some(preimage.to_hex()); + mutiny_invoice.preimage = Some(preimage.to_lower_hex_string()); mutiny_invoice.status = HTLCStatus::Succeeded; mutiny_invoice.last_updated = utils::now().as_secs(); mutiny_invoice.fees_paid = Some(0); @@ -1651,7 +1661,7 @@ mod wasm_test { match response.result { Some(ResponseResult::PayInvoice(PayInvoiceResponseResult { preimage: pre })) => { - assert_eq!(pre, preimage.to_hex()); + assert_eq!(pre, preimage.to_lower_hex_string()); } _ => panic!("wrong response"), } @@ -1660,7 +1670,10 @@ mod wasm_test { SpendingConditions::Budget(budget) => { assert_eq!(budget.payments.len(), 1); assert_eq!(budget.payments[0].amt, amount_msats / 1_000); - assert_eq!(budget.payments[0].hash, invoice.payment_hash().to_hex()); + assert_eq!( + budget.payments[0].hash, + invoice.payment_hash().into_32().to_lower_hex_string() + ); } _ => panic!("wrong spending conditions"), } diff --git a/mutiny-core/src/onchain.rs b/mutiny-core/src/onchain.rs index 4b3a5b7da..ae2aa31d0 100644 --- a/mutiny-core/src/onchain.rs +++ b/mutiny-core/src/onchain.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use std::collections::{BTreeMap, HashSet}; +use std::collections::HashSet; use std::str::FromStr; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; @@ -8,14 +8,15 @@ use bdk::chain::{BlockId, ConfirmationTime}; use bdk::psbt::PsbtUtils; use bdk::template::DescriptorTemplateOut; use bdk::wallet::{AddressIndex, Update}; -use bdk::{FeeRate, LocalUtxo, SignOptions, TransactionDetails, Wallet}; +use bdk::{FeeRate, LocalOutput, SignOptions, Wallet}; +use bdk_chain::indexed_tx_graph::Indexer; use bdk_esplora::EsploraAsyncExt; +use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; use bitcoin::consensus::serialize; -use bitcoin::hashes::hex::ToHex; use bitcoin::psbt::{Input, PartiallySignedTransaction}; -use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; -use bitcoin::{Address, Network, OutPoint, Script, Transaction, Txid}; +use bitcoin::{Address, Network, OutPoint, ScriptBuf, Transaction, Txid}; use esplora_client::AsyncClient; +use hex_conservative::DisplayHex; use lightning::events::bump_transaction::{Utxo, WalletSource}; use lightning::util::logger::Logger; use lightning::{log_debug, log_error, log_info, log_trace, log_warn}; @@ -24,12 +25,11 @@ use crate::error::MutinyError; use crate::fees::MutinyFeeEstimator; use crate::labels::*; use crate::logging::MutinyLogger; -use crate::storage::{MutinyStorage, OnChainStorage}; +use crate::nodemanager::TransactionDetails; +use crate::storage::{MutinyStorage, OnChainStorage, KEYCHAIN_STORE_KEY, NEED_FULL_SYNC_KEY}; use crate::utils::{now, sleep}; -pub(crate) const DEFAULT_STOP_GAP: usize = 10; pub(crate) const FULL_SYNC_STOP_GAP: usize = 150; -#[cfg(not(test))] pub(crate) const RESTORE_SYNC_STOP_GAP: usize = 20; #[derive(Clone)] @@ -57,12 +57,39 @@ impl OnChainWallet { let (receive_descriptor_template, change_descriptor_template) = get_tr_descriptors_for_extended_key(xprivkey, network, account_number)?; - let wallet = Wallet::new( - receive_descriptor_template, - Some(change_descriptor_template), + // if we have a keychain set, load the wallet, otherwise create one + let load_wallet_res = Wallet::load( + receive_descriptor_template.clone(), + Some(change_descriptor_template.clone()), OnChainStorage(db.clone()), - network, - )?; + ); + let wallet = match load_wallet_res { + Ok(wallet) => wallet, + Err(bdk::wallet::LoadError::NotInitialized) => { + // we don't have a bdk wallet, create one + Wallet::new( + receive_descriptor_template, + Some(change_descriptor_template), + OnChainStorage(db.clone()), + network, + )? + } + Err(bdk::wallet::LoadError::Load(_)) => { + // failed to read storage, means we have old encoding and need to delete and re-init wallet + db.delete(&[KEYCHAIN_STORE_KEY])?; + db.set_data(NEED_FULL_SYNC_KEY.to_string(), true, None)?; + Wallet::new( + receive_descriptor_template, + Some(change_descriptor_template), + OnChainStorage(db.clone()), + network, + )? + } + Err(e) => { + log_error!(logger, "Failed to load wallet: {e}"); + return Err(MutinyError::WalletOperationFailed); + } + }; Ok(OnChainWallet { wallet: Arc::new(RwLock::new(wallet)), @@ -78,7 +105,7 @@ impl OnChainWallet { pub async fn broadcast_transaction(&self, tx: Transaction) -> Result<(), MutinyError> { let txid = tx.txid(); log_info!(self.logger, "Broadcasting transaction: {txid}"); - log_debug!(self.logger, "Transaction: {}", serialize(&tx).to_hex()); + log_debug!(self.logger, "Transaction: {}", serialize(&tx).as_hex()); if let Err(e) = self.blockchain.broadcast(&tx).await { log_error!(self.logger, "Failed to broadcast transaction ({txid}): {e}"); @@ -106,11 +133,9 @@ impl OnChainWallet { // get wallet lock for writing and apply the update match self.wallet.try_write() { Ok(mut wallet) => match wallet.apply_update(update) { - Ok(changed) => { - // commit the changes if there were any - if changed { - wallet.commit()?; - } + Ok(_) => { + // commit the changes + wallet.commit()?; Ok(true) } @@ -137,50 +162,56 @@ impl OnChainWallet { } pub async fn sync(&self) -> Result<(), MutinyError> { + // if we need a full sync from a restore + if self.storage.get(NEED_FULL_SYNC_KEY)?.unwrap_or_default() { + self.full_sync(RESTORE_SYNC_STOP_GAP).await?; + self.storage.delete(&[NEED_FULL_SYNC_KEY])?; + } // get first wallet lock that only needs to read - let (checkpoints, spks, txids) = { + let (spks, txids, chain, prev_tip) = { if let Ok(wallet) = self.wallet.try_read() { - let checkpoints = wallet.checkpoints(); - let spk_vec = wallet .spk_index() - .unused_spks(..) - .map(|(k, v)| (*k, v.clone())) + .unused_spks() + .map(|(_, _, v)| ScriptBuf::from(v)) .collect::>(); - let mut spk_map = BTreeMap::new(); - for ((a, b), c) in spk_vec { - spk_map.entry(a).or_insert_with(Vec::new).push((b, c)); - } - let chain = wallet.local_chain(); - let chain_tip = chain.tip().unwrap_or_default(); + let chain_tip = chain.tip().block_id(); let unconfirmed_txids = wallet .tx_graph() .list_chain_txs(chain, chain_tip) - .filter(|canonical_tx| !canonical_tx.observed_as.is_confirmed()) - .map(|canonical_tx| canonical_tx.node.txid) + .filter(|canonical_tx| !canonical_tx.chain_position.is_confirmed()) + .map(|canonical_tx| canonical_tx.tx_node.txid) .collect::>(); - (checkpoints.clone(), spk_map, unconfirmed_txids) + ( + spk_vec, + unconfirmed_txids, + chain.clone(), + wallet.latest_checkpoint(), + ) } else { log_error!(self.logger, "Could not get wallet lock to sync"); return Err(MutinyError::WalletOperationFailed); } }; - let update = self + let update_graph = self .blockchain - .scan( - &checkpoints, - spks, - txids, - core::iter::empty(), - DEFAULT_STOP_GAP, - 5, - ) + .sync(spks, txids, core::iter::empty(), 5) .await?; + let missing_heights = update_graph.missing_heights(&chain); + let chain_update = self + .blockchain + .update_local_chain(prev_tip, missing_heights) + .await?; + let update = Update { + graph: update_graph, + chain: Some(chain_update), + ..Default::default() + }; for _ in 0..10 { let successful = self.try_commit_update(update.clone())?; @@ -199,29 +230,30 @@ impl OnChainWallet { pub async fn full_sync(&self, gap: usize) -> Result<(), MutinyError> { // get first wallet lock that only needs to read - let (checkpoints, spks) = { + let (spks, prev_tip, chain) = { if let Ok(wallet) = self.wallet.try_read() { - let checkpoints = wallet.checkpoints(); - let spks = wallet.spks_of_all_keychains(); - - (checkpoints.clone(), spks) + ( + wallet.all_unbounded_spk_iters(), + wallet.latest_checkpoint(), + wallet.local_chain().clone(), + ) } else { log_error!(self.logger, "Could not get wallet lock to sync"); return Err(MutinyError::WalletOperationFailed); } }; - let update = self + let (update_graph, last_active_indices) = self.blockchain.full_scan(spks, gap, 5).await?; + let missing_heights = update_graph.missing_heights(&chain); + let chain_update = self .blockchain - .scan( - &checkpoints, - spks, - core::iter::empty(), - core::iter::empty(), - gap, - 5, - ) + .update_local_chain(prev_tip, missing_heights) .await?; + let update = Update { + last_active_indices, + graph: update_graph, + chain: Some(chain_update), + }; // get new wallet lock for writing and apply the update for _ in 0..10 { @@ -264,7 +296,7 @@ impl OnChainWallet { let mut wallet = self.wallet.try_write()?; // if we already have the transaction, we don't need to insert it - if wallet.get_tx(tx.txid(), false).is_none() { + if wallet.get_tx(tx.txid()).is_none() { // insert tx and commit changes wallet.insert_tx(tx, position)?; wallet.commit()?; @@ -281,7 +313,7 @@ impl OnChainWallet { Ok(()) } - pub fn list_utxos(&self) -> Result, MutinyError> { + pub fn list_utxos(&self) -> Result, MutinyError> { Ok(self.wallet.try_read()?.list_unspent().collect()) } @@ -294,11 +326,11 @@ impl OnChainWallet { .transactions() .filter_map(|tx| { // skip txs that were not relevant to our bdk wallet - if wallet.spk_index().is_relevant(tx.node.tx) { - let (sent, received) = wallet.spk_index().sent_and_received(tx.node.tx); + if wallet.spk_index().is_tx_relevant(tx.tx_node.tx) { + let (sent, received) = wallet.spk_index().sent_and_received(tx.tx_node.tx); let transaction = if include_raw { - Some(tx.node.tx.clone()) + Some(tx.tx_node.tx.clone()) } else { None }; @@ -306,7 +338,7 @@ impl OnChainWallet { // todo bdk is making an easy function for this // calculate fee if possible let inputs = tx - .node + .tx_node .tx .input .iter() @@ -314,19 +346,20 @@ impl OnChainWallet { wallet .spk_index() .txout(txin.previous_output) - .map(|(_, txout)| txout.value) + .map(|(_, _, txout)| txout.value) }) .sum::>(); - let outputs = tx.node.tx.output.iter().map(|txout| txout.value).sum(); + let outputs = tx.tx_node.tx.output.iter().map(|txout| txout.value).sum(); let fee = inputs.map(|inputs| inputs.saturating_sub(outputs)); Some(TransactionDetails { transaction, - txid: tx.node.txid, + txid: tx.tx_node.txid, received, sent, fee, - confirmation_time: tx.observed_as.cloned().into(), + confirmation_time: tx.chain_position.cloned().into(), + labels: vec![], }) } else { None @@ -342,12 +375,28 @@ impl OnChainWallet { Err(MutinyError::WalletOperationFailed) } - pub fn get_transaction( - &self, - txid: Txid, - include_raw: bool, - ) -> Result, MutinyError> { - Ok(self.wallet.try_read()?.get_tx(txid, include_raw)) + pub fn get_transaction(&self, txid: Txid) -> Result, MutinyError> { + let wallet = self.wallet.try_read()?; + let bdk_tx = wallet.get_tx(txid); + + match bdk_tx { + None => Ok(None), + Some(tx) => { + let (sent, received) = wallet.sent_and_received(tx.tx_node.tx); + let fee = wallet.calculate_fee(tx.tx_node.tx).ok(); + let details = TransactionDetails { + transaction: Some(tx.tx_node.tx.to_owned()), + txid, + received, + sent, + fee, + confirmation_time: tx.chain_position.cloned().into(), + labels: vec![], + }; + + Ok(Some(details)) + } + } } #[allow(dead_code)] @@ -425,16 +474,12 @@ impl OnChainWallet { amount: u64, fee_rate: Option, ) -> Result { - if !send_to.is_valid_for_network(self.network) { - return Err(MutinyError::IncorrectNetwork(send_to.network)); - } - self.create_signed_psbt_to_spk(send_to.script_pubkey(), amount, fee_rate) } pub fn create_signed_psbt_to_spk( &self, - spk: Script, + spk: ScriptBuf, amount: u64, fee_rate: Option, ) -> Result { @@ -446,7 +491,7 @@ impl OnChainWallet { let sat_per_kwu = self.fees.get_normal_fee_rate(); FeeRate::from_sat_per_kwu(sat_per_kwu as f32) }; - let (mut psbt, details) = { + let mut psbt = { let mut builder = wallet.build_tx(); builder .add_recipient(spk, amount) @@ -454,7 +499,6 @@ impl OnChainWallet { .fee_rate(fee_rate); builder.finish()? }; - log_debug!(self.logger, "Transaction details: {details:#?}"); log_debug!(self.logger, "Unsigned PSBT: {psbt}"); let finalized = wallet.sign(&mut psbt, SignOptions::default())?; log_debug!(self.logger, "finalized: {finalized}"); @@ -534,7 +578,7 @@ impl OnChainWallet { pub fn create_sweep_psbt( &self, - spk: Script, + spk: ScriptBuf, fee_rate: Option, ) -> Result { let mut wallet = self.wallet.try_write()?; @@ -545,7 +589,7 @@ impl OnChainWallet { let sat_per_kwu = self.fees.get_normal_fee_rate(); FeeRate::from_sat_per_kwu(sat_per_kwu as f32) }; - let (mut psbt, details) = { + let mut psbt = { let mut builder = wallet.build_tx(); builder .drain_wallet() // Spend all outputs in this wallet. @@ -554,7 +598,6 @@ impl OnChainWallet { .fee_rate(fee_rate); builder.finish()? }; - log_debug!(self.logger, "Transaction details: {details:#?}"); log_debug!(self.logger, "Unsigned PSBT: {psbt}"); let finalized = wallet.sign(&mut psbt, SignOptions::default())?; log_debug!(self.logger, "finalized: {finalized}"); @@ -567,10 +610,6 @@ impl OnChainWallet { labels: Vec, fee_rate: Option, ) -> Result { - if !destination_address.is_valid_for_network(self.network) { - return Err(MutinyError::IncorrectNetwork(destination_address.network)); - } - let psbt = self.create_sweep_psbt(destination_address.script_pubkey(), fee_rate)?; self.label_psbt(&psbt, labels)?; @@ -588,12 +627,12 @@ impl OnChainWallet { pub(crate) fn create_sweep_psbt_to_output( &self, utxos: &[OutPoint], - spk: Script, + spk: ScriptBuf, amount_sats: u64, absolute_fee: u64, ) -> Result { let mut wallet = self.wallet.try_write()?; - let (mut psbt, details) = { + let mut psbt = { let mut builder = wallet.build_tx(); builder .manually_selected_only() @@ -603,7 +642,6 @@ impl OnChainWallet { .enable_rbf(); builder.finish()? }; - log_debug!(self.logger, "Transaction details: {details:#?}"); log_debug!(self.logger, "Unsigned PSBT: {psbt}"); let finalized = wallet.sign(&mut psbt, SignOptions::default())?; log_debug!(self.logger, "finalized: {finalized}"); @@ -612,7 +650,7 @@ impl OnChainWallet { pub fn estimate_tx_fee( &self, - spk: Script, + spk: ScriptBuf, amount: u64, fee_rate: Option, ) -> Result { @@ -623,7 +661,7 @@ impl OnChainWallet { pub fn estimate_sweep_tx_fee( &self, - spk: Script, + spk: ScriptBuf, fee_rate: Option, ) -> Result { let psbt = self.create_sweep_psbt(spk, fee_rate)?; @@ -639,7 +677,7 @@ impl OnChainWallet { // build RBF fee bump tx let mut builder = wallet.build_fee_bump(txid)?; builder.fee_rate(FeeRate::from_sat_per_vb(new_fee_rate)); - let (mut psbt, _) = builder.finish()?; + let mut psbt = builder.finish()?; wallet.sign(&mut psbt, SignOptions::default())?; psbt.extract_tx() @@ -684,6 +722,7 @@ pub(crate) fn coin_type_from_network(network: Network) -> u32 { Network::Testnet => 1, Network::Signet => 1, Network::Regtest => 1, + net => panic!("Got unknown network: {net}!"), } } @@ -696,6 +735,7 @@ pub(crate) fn get_esplora_url(network: Network, user_provided_url: Option "https://mempool.space/testnet/api", Network::Signet => "https://mutinynet.com/api", Network::Regtest => "http://localhost:3003", + net => panic!("Got unknown network: {net}!"), } .to_string() } @@ -716,40 +756,24 @@ impl WalletSource for OnChainWallet { Ok(utxos) } - fn get_change_script(&self) -> Result { + fn get_change_script(&self) -> Result { let mut wallet = self.wallet.try_write().map_err(|_| ())?; let addr = wallet - .get_internal_address(AddressIndex::LastUnused) + .try_get_internal_address(AddressIndex::New) + .map_err(|_| ())? .address; Ok(addr.script_pubkey()) } - fn sign_tx(&self, tx: Transaction) -> Result { + fn sign_psbt(&self, mut psbt: PartiallySignedTransaction) -> Result { let wallet = self.wallet.try_read().map_err(|e| { log_error!( self.logger, "Could not get wallet lock to sign transaction: {e:?}" ) })?; - let mut psbt = PartiallySignedTransaction::from_unsigned_tx(tx).map_err(|e| { - log_error!(self.logger, "Could not create PSBT from transaction: {e:?}") - })?; - // set witness_utxo for inputs - wallet.list_unspent().for_each(|u| { - psbt.unsigned_tx - .input - .iter() - .enumerate() - .for_each(|(i, txin)| { - if txin.previous_output == u.outpoint { - psbt.inputs[i].witness_utxo = Some(u.txout.clone()); - } - }) - }); - - // need to trust witness_utxo for signing since that's what we set above - // this is safe because we added it ourselves + // need to trust witness_utxo for signing since that's LDK sets in the psbt let sign_options = SignOptions { trust_witness_utxo: true, ..Default::default() @@ -785,17 +809,15 @@ mod tests { let cipher = encryption_key_from_pass(&pass).unwrap(); let db = MemoryStorage::new(Some(pass), Some(cipher), None); let logger = Arc::new(MutinyLogger::default()); - let network = Network::Testnet; let fees = Arc::new(MutinyFeeEstimator::new( db.clone(), - network, esplora.clone(), logger.clone(), )); let stop = Arc::new(AtomicBool::new(false)); - let xpriv = ExtendedPrivKey::new_master(network, &mnemonic.to_seed("")).unwrap(); + let xpriv = ExtendedPrivKey::new_master(Network::Testnet, &mnemonic.to_seed("")).unwrap(); - OnChainWallet::new(xpriv, db, network, esplora, fees, stop, logger).unwrap() + OnChainWallet::new(xpriv, db, Network::Testnet, esplora, fees, stop, logger).unwrap() } #[test] @@ -814,15 +836,21 @@ mod tests { let psbt = PartiallySignedTransaction::from_str("cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA").unwrap(); // set label for input - let input_addr = Address::from_str("2Mx6uYKYGW5J6sV59e5NsdtCTsJYRxednbx").unwrap(); + let input_addr = Address::from_str("2Mx6uYKYGW5J6sV59e5NsdtCTsJYRxednbx") + .unwrap() + .assume_checked(); let prev_label = "previous".to_string(); wallet .storage .set_address_labels(input_addr, vec![prev_label]) .unwrap(); - let send_to_addr = Address::from_str("mrKjeffvbnmKJURrLNdqLkfrptLrFtnkFx").unwrap(); - let change_addr = Address::from_str("mqfKJuj2Ea4RtXsKawQWrqosGeHFTrp6iZ").unwrap(); + let send_to_addr = Address::from_str("mrKjeffvbnmKJURrLNdqLkfrptLrFtnkFx") + .unwrap() + .assume_checked(); + let change_addr = Address::from_str("mqfKJuj2Ea4RtXsKawQWrqosGeHFTrp6iZ") + .unwrap() + .assume_checked(); let label = "test".to_string(); let result = wallet.label_psbt(&psbt, vec![label.clone()]); @@ -844,7 +872,11 @@ mod tests { let label = wallet.storage.get_label(&label).unwrap(); assert!(label.is_some()); assert_eq!(label.clone().unwrap().addresses.len(), 2); - assert!(label.clone().unwrap().addresses.contains(&send_to_addr)); - assert!(label.unwrap().addresses.contains(&change_addr)); + assert!(label + .clone() + .unwrap() + .addresses + .contains(&send_to_addr.to_string())); + assert!(label.unwrap().addresses.contains(&change_addr.to_string())); } } diff --git a/mutiny-core/src/peermanager.rs b/mutiny-core/src/peermanager.rs index 52b3f5257..0435dc4d5 100644 --- a/mutiny-core/src/peermanager.rs +++ b/mutiny-core/src/peermanager.rs @@ -6,7 +6,9 @@ use crate::{error::MutinyError, fees::MutinyFeeEstimator}; use crate::{gossip, ldkstorage::PhantomChannelManager, logging::MutinyLogger}; use crate::{gossip::read_peer_info, node::PubkeyConnectionInfo}; use crate::{keymanager::PhantomKeysManager, node::ConnectionType}; -use bitcoin::secp256k1::PublicKey; +use bitcoin::key::{Secp256k1, Verification}; +use bitcoin::secp256k1::{PublicKey, Signing}; +use lightning::blinded_path::BlindedPath; use lightning::events::{MessageSendEvent, MessageSendEventsProvider}; use lightning::ln::features::{InitFeatures, NodeFeatures}; use lightning::ln::msgs; @@ -14,8 +16,9 @@ use lightning::ln::msgs::{LightningError, RoutingMessageHandler}; use lightning::ln::peer_handler::PeerHandleError; use lightning::ln::peer_handler::PeerManager as LdkPeerManager; use lightning::log_warn; -use lightning::onion_message::{Destination, MessageRouter, OnionMessagePath}; +use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath}; use lightning::routing::gossip::NodeId; +use lightning::sign::EntropySource; use lightning::util::logger::Logger; use lightning::{ ln::{msgs::SocketAddress, peer_handler::SocketDescriptor as LdkSocketDescriptor}, @@ -327,14 +330,27 @@ impl MessageRouter for LspMessageRouter { Ok(OnionMessagePath { intermediate_nodes: vec![], destination, + first_node_addresses: None, }) } else { Ok(OnionMessagePath { intermediate_nodes: self.intermediate_nodes.clone(), destination, + first_node_addresses: None, }) } } + + fn create_blinded_paths( + &self, + _recipient: PublicKey, + _peers: Vec, + _entropy_source: &ES, + _secp_ctx: &Secp256k1, + ) -> Result, ()> { + // Bolt12 not yet supported + Err(()) + } } pub(crate) async fn connect_peer_if_necessary( diff --git a/mutiny-core/src/scorer.rs b/mutiny-core/src/scorer.rs index 44fd35d43..84e9d97c5 100644 --- a/mutiny-core/src/scorer.rs +++ b/mutiny-core/src/scorer.rs @@ -1,4 +1,5 @@ use crate::{logging::MutinyLogger, node::NetworkGraph}; +use lightning::routing::router::CandidateRouteHop; use lightning::{ routing::{ gossip::NodeId, @@ -10,6 +11,7 @@ use lightning::{ }, util::ser::{Writeable, Writer}, }; +use std::time::Duration; use std::{collections::HashSet, str::FromStr, sync::Arc}; const HUB_BASE_DISCOUNT_PENALTY_MSAT: u64 = 100_000; @@ -290,8 +292,44 @@ impl HubPreferentialScorer { } } - fn is_preferred_hub(&self, node_id: &NodeId) -> bool { - self.preferred_hubs_set.contains(node_id) + fn is_source_preferred_hub(&self, candidate: &CandidateRouteHop) -> bool { + match candidate { + CandidateRouteHop::FirstHop(_) => false, // source of first hop is us + CandidateRouteHop::PublicHop(hop) => { + self.preferred_hubs_set.contains(hop.info.source()) + } + CandidateRouteHop::PrivateHop(hop) => { + let source = hop.hint.src_node_id; + let node_id = NodeId::from_pubkey(&source); + self.preferred_hubs_set.contains(&node_id) + } + CandidateRouteHop::Blinded(hop) => { + // we can prefer blinded paths with hub introduction points + let (_, path) = hop.hint; + let node_id = NodeId::from_pubkey(&path.introduction_node_id); + self.preferred_hubs_set.contains(&node_id) + } + CandidateRouteHop::OneHopBlinded(hop) => { + // one hop is just the introduction node which is a known node id + let (_, path) = hop.hint; + let node_id = NodeId::from_pubkey(&path.introduction_node_id); + self.preferred_hubs_set.contains(&node_id) + } + } + } + + fn is_target_preferred_hub(&self, candidate: &CandidateRouteHop) -> bool { + match candidate { + CandidateRouteHop::FirstHop(hop) => self.preferred_hubs_set.contains(hop.payer_node_id), + CandidateRouteHop::PublicHop(hop) => { + self.preferred_hubs_set.contains(hop.info.target()) + } + CandidateRouteHop::PrivateHop(hop) => { + self.preferred_hubs_set.contains(hop.target_node_id) + } + CandidateRouteHop::Blinded(_) => false, // the target of a blinded path is unknown + CandidateRouteHop::OneHopBlinded(_) => false, // the target of a blinded path is unknown + } } } @@ -300,31 +338,31 @@ impl ScoreLookUp for HubPreferentialScorer { fn channel_penalty_msat( &self, - short_channel_id: u64, - source: &NodeId, - target: &NodeId, + candidate: &CandidateRouteHop, usage: ChannelUsage, score_params: &Self::ScoreParams, ) -> u64 { // normal penalty from the inner scorer - let mut penalty = - self.inner - .channel_penalty_msat(short_channel_id, source, target, usage, score_params); + let mut penalty = self + .inner + .channel_penalty_msat(candidate, usage, score_params); let hub_to_hub_min_penalty = (score_params.base_penalty_msat as f64 * 0.5) as u64; let entering_highway_min_penalty = (score_params.base_penalty_msat as f64 * 0.7) as u64; - if self.is_preferred_hub(source) && self.is_preferred_hub(target) { + let is_source_preferred_hub = self.is_source_preferred_hub(candidate); + let is_target_preferred_hub = self.is_target_preferred_hub(candidate); + if is_source_preferred_hub && is_target_preferred_hub { // Both the source and target are on the "hub highway" penalty = penalty.saturating_mul(5).saturating_div(10); // 50% discount penalty = penalty .saturating_sub(HUB_BASE_DISCOUNT_PENALTY_MSAT) .max(hub_to_hub_min_penalty); // Base fee discount - } else if self.is_preferred_hub(target) { + } else if is_target_preferred_hub { // Only the target is a preferred hub (entering the "hub highway") penalty = penalty.saturating_mul(7).saturating_div(10); // 30% discount penalty = penalty.max(entering_highway_min_penalty); - } else if self.is_preferred_hub(source) { + } else if is_source_preferred_hub { // Only the source is a preferred hub (leaving the "hub highway") // No discount here penalty = penalty.max(score_params.base_penalty_msat); @@ -341,20 +379,32 @@ impl ScoreLookUp for HubPreferentialScorer { } impl ScoreUpdate for HubPreferentialScorer { - fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) { - self.inner.payment_path_failed(path, short_channel_id) + fn payment_path_failed( + &mut self, + path: &Path, + short_channel_id: u64, + duration_since_epoch: Duration, + ) { + self.inner + .payment_path_failed(path, short_channel_id, duration_since_epoch) + } + + fn payment_path_successful(&mut self, path: &Path, duration_since_epoch: Duration) { + self.inner + .payment_path_successful(path, duration_since_epoch) } - fn payment_path_successful(&mut self, path: &Path) { - self.inner.payment_path_successful(path) + fn probe_failed(&mut self, path: &Path, short_channel_id: u64, duration_since_epoch: Duration) { + self.inner + .probe_failed(path, short_channel_id, duration_since_epoch) } - fn probe_failed(&mut self, path: &Path, short_channel_id: u64) { - self.inner.probe_failed(path, short_channel_id) + fn probe_successful(&mut self, path: &Path, duration_since_epoch: Duration) { + self.inner.probe_successful(path, duration_since_epoch) } - fn probe_successful(&mut self, path: &Path) { - self.inner.probe_successful(path) + fn time_passed(&mut self, duration_since_epoch: Duration) { + self.inner.time_passed(duration_since_epoch) } } diff --git a/mutiny-core/src/storage.rs b/mutiny-core/src/storage.rs index 812e01e85..21b2e0970 100644 --- a/mutiny-core/src/storage.rs +++ b/mutiny-core/src/storage.rs @@ -14,10 +14,9 @@ use crate::{ldkstorage::CHANNEL_MANAGER_KEY, utils::sleep}; use async_trait::async_trait; use bdk::chain::{Append, PersistBackend}; use bip39::Mnemonic; -use bitcoin::hashes::hex::ToHex; -use bitcoin::hashes::Hash; +use bitcoin::secp256k1::ThirtyTwoByteHash; use futures_util::lock::Mutex; -use hex::FromHex; +use hex_conservative::*; use lightning::{ln::PaymentHash, util::logger::Logger}; use lightning::{log_error, log_trace}; use serde::{Deserialize, Serialize}; @@ -785,17 +784,9 @@ impl MutinyStorage for () { fn payment_key(inbound: bool, payment_hash: &[u8; 32]) -> String { if inbound { - format!( - "{}{}", - PAYMENT_INBOUND_PREFIX_KEY, - payment_hash.to_hex().as_str() - ) + format!("{}{}", PAYMENT_INBOUND_PREFIX_KEY, payment_hash.as_hex()) } else { - format!( - "{}{}", - PAYMENT_OUTBOUND_PREFIX_KEY, - payment_hash.to_hex().as_str() - ) + format!("{}{}", PAYMENT_OUTBOUND_PREFIX_KEY, payment_hash.as_hex()) } } @@ -817,12 +808,13 @@ pub(crate) fn get_payment_info( logger: &MutinyLogger, ) -> Result<(PaymentInfo, bool), MutinyError> { // try inbound first - if let Some(payment_info) = read_payment_info(storage, payment_hash.as_inner(), true, logger) { + let payment_hash = payment_hash.into_32(); + if let Some(payment_info) = read_payment_info(storage, &payment_hash, true, logger) { return Ok((payment_info, true)); } // if no inbound check outbound - match read_payment_info(storage, payment_hash.as_inner(), false, logger) { + match read_payment_info(storage, &payment_hash, false, logger) { Some(payment_info) => Ok((payment_info, false)), None => Err(MutinyError::NotFound), } @@ -901,13 +893,8 @@ where } } - fn load_from_persistence(&mut self) -> Result { - if let Some(k) = self.0.get_data(KEYCHAIN_STORE_KEY)? { - Ok(k) - } else { - // If there is no keychain store, we return an empty one - Ok(K::default()) - } + fn load_from_persistence(&mut self) -> Result, Self::LoadError> { + self.0.get_data(KEYCHAIN_STORE_KEY) } } diff --git a/mutiny-core/src/test_utils.rs b/mutiny-core/src/test_utils.rs index 018d01a88..c9ce0f35a 100644 --- a/mutiny-core/src/test_utils.rs +++ b/mutiny-core/src/test_utils.rs @@ -98,7 +98,6 @@ pub(crate) async fn create_node(storage: S) -> Node { let esplora = Arc::new(esplora); let fee_estimator = Arc::new(MutinyFeeEstimator::new( storage.clone(), - network, esplora.clone(), logger.clone(), )); @@ -186,7 +185,7 @@ macro_rules! log { } use bitcoin::hashes::{sha256, Hash}; use bitcoin::secp256k1::{Secp256k1, SecretKey}; -use bitcoin::{util::bip32::ExtendedPrivKey, Network}; +use bitcoin::{bip32::ExtendedPrivKey, Network}; use lightning::ln::PaymentSecret; use lightning::routing::scoring::ProbabilisticScoringDecayParameters; use lightning_invoice::{Bolt11Invoice, InvoiceBuilder}; diff --git a/mutiny-core/src/utils.rs b/mutiny-core/src/utils.rs index 063b73996..993465243 100644 --- a/mutiny-core/src/utils.rs +++ b/mutiny-core/src/utils.rs @@ -7,9 +7,11 @@ use futures::{ future::{self, Either}, pin_mut, }; +use hex_conservative::DisplayHex; use lightning::routing::scoring::{LockableScore, ScoreLookUp, ScoreUpdate}; use lightning::util::ser::Writeable; use lightning::util::ser::Writer; +use lightning_invoice::Bolt11Invoice; use nostr::key::XOnlyPublicKey; use nostr::nips::nip05; use nostr::{Event, Filter, FromBech32, JsonUtil, Kind, Metadata}; @@ -24,6 +26,7 @@ pub(crate) fn min_lightning_amount(network: Network) -> u64 { match network { Network::Bitcoin => 100_000, Network::Testnet | Network::Signet | Network::Regtest => 10_000, + net => unreachable!("Unknown network {net}!"), } } @@ -263,3 +266,26 @@ pub const HODL_INVOICE_NODES: [&str; 5] = [ "0282eb467bc073833a039940392592bf10cf338a830ba4e392c1667d7697654c7e", // Robosats "037ff12b6a4e4bcb4b944b6d20af08cdff61b3461c1dff0d00a88697414d891bc7", // Robosats ]; + +pub fn is_hodl_invoice(invoice: &Bolt11Invoice) -> bool { + let pubkey = invoice + .recover_payee_pub_key() + .serialize() + .to_lower_hex_string(); + HODL_INVOICE_NODES.contains(&pubkey.as_str()) +} + +/// Coverts from our Bolt11Invoice type to fedimint's +pub fn convert_to_fedimint_invoice( + invoice: &Bolt11Invoice, +) -> fedimint_ln_common::lightning_invoice::Bolt11Invoice { + fedimint_ln_common::lightning_invoice::Bolt11Invoice::from_str(&invoice.to_string()) + .expect("just converting types") +} + +/// Coverts from fedimint's Bolt11Invoice type to ours +pub fn convert_from_fedimint_invoice( + invoice: &fedimint_ln_common::lightning_invoice::Bolt11Invoice, +) -> Bolt11Invoice { + Bolt11Invoice::from_str(&invoice.to_string()).expect("just converting types") +} diff --git a/mutiny-core/src/vss.rs b/mutiny-core/src/vss.rs index 1c9dac6be..d1143deb4 100644 --- a/mutiny-core/src/vss.rs +++ b/mutiny-core/src/vss.rs @@ -2,8 +2,8 @@ use crate::auth::MutinyAuthClient; use crate::encrypt::{decrypt_with_key, encrypt_with_key}; use crate::{error::MutinyError, logging::MutinyLogger}; use anyhow::anyhow; -use bitcoin::hashes::hex::ToHex; use bitcoin::secp256k1::{Secp256k1, SecretKey}; +use hex_conservative::DisplayHex; use lightning::util::logger::*; use lightning::{log_error, log_info}; use reqwest::{Method, Url}; @@ -98,7 +98,10 @@ impl MutinyVssClient { logger: Arc, ) -> Self { log_info!(logger, "Creating unauthenticated vss client"); - let pk = encryption_key.public_key(&Secp256k1::new()).to_hex(); + let pk = encryption_key + .public_key(&Secp256k1::new()) + .serialize() + .to_lower_hex_string(); Self { auth_client: None, client: Some(reqwest::Client::new()), diff --git a/mutiny-wasm/Cargo.toml b/mutiny-wasm/Cargo.toml index 1f9282f4a..3c1ddecb6 100644 --- a/mutiny-wasm/Cargo.toml +++ b/mutiny-wasm/Cargo.toml @@ -24,12 +24,12 @@ wasm-bindgen = "0.2.88" wasm-bindgen-futures = "0.4.38" serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } -bitcoin = { version = "0.29.2", default-features = false, features = ["std", "serde", "secp-recovery", "rand"] } -lightning = { version = "0.0.118", default-features = false, features = ["std"] } -lightning-invoice = { version = "0.26.0" } +bitcoin = { version = "0.30.2", default-features = false, features = ["std", "serde", "secp-recovery", "rand"] } +lightning = { version = "0.0.121", default-features = false, features = ["std"] } +lightning-invoice = { version = "0.29.0" } thiserror = "1.0" instant = { version = "0.1", features = ["wasm-bindgen"] } -lnurl-rs = { version = "0.3.1", default-features = false } +lnurl-rs = { version = "0.4.1", default-features = false } nostr = { version = "0.27.0", default-features = false, features = ["nip04", "nip05", "nip07", "nip47", "nip57"] } wasm-logger = "0.2.0" log = "0.4.17" @@ -41,6 +41,7 @@ getrandom = { version = "0.2", features = ["js"] } futures = "0.3.25" urlencoding = "2.1.2" once_cell = "1.18.0" +hex-conservative = "0.1.1" payjoin = { version = "0.13.0", features = ["send", "base64"] } fedimint-core = { git = "https://github.com/fedimint/fedimint", rev = "6a923ee10c3a578cd835044e3fdd94aa5123735a" } diff --git a/mutiny-wasm/src/error.rs b/mutiny-wasm/src/error.rs index 7af60598f..77ac7e99f 100644 --- a/mutiny-wasm/src/error.rs +++ b/mutiny-wasm/src/error.rs @@ -1,4 +1,3 @@ -use bitcoin::Network; use lightning_invoice::ParseOrSemanticError; use log::error; use mutiny_core::error::{MutinyError, MutinyStorageError}; @@ -28,7 +27,7 @@ pub enum MutinyJsError { ConnectionFailed, /// The invoice or address is on a different network #[error("The invoice or address is on a different network.")] - IncorrectNetwork(Network), + IncorrectNetwork, /// Payment of the given invoice has already been initiated. #[error("An invoice must not get payed twice.")] NonUniquePaymentHash, @@ -173,7 +172,7 @@ impl From for MutinyJsError { MutinyError::NotFound => MutinyJsError::NotFound, MutinyError::FundingTxCreationFailed => MutinyJsError::FundingTxCreationFailed, MutinyError::ConnectionFailed => MutinyJsError::ConnectionFailed, - MutinyError::IncorrectNetwork(net) => MutinyJsError::IncorrectNetwork(net), + MutinyError::IncorrectNetwork => MutinyJsError::IncorrectNetwork, MutinyError::NonUniquePaymentHash => MutinyJsError::NonUniquePaymentHash, MutinyError::PaymentTimeout => MutinyJsError::PaymentTimeout, MutinyError::InvoiceInvalid => MutinyJsError::InvoiceInvalid, @@ -243,8 +242,8 @@ impl From for MutinyJsError { } } -impl From for MutinyJsError { - fn from(_: bitcoin::util::address::Error) -> Self { +impl From for MutinyJsError { + fn from(_: bitcoin::address::Error) -> Self { Self::JsonReadWriteError } } @@ -255,12 +254,6 @@ impl From for MutinyJsError { } } -impl From for MutinyJsError { - fn from(_: nostr::secp256k1::Error) -> Self { - Self::InvalidArgumentsError - } -} - impl From for MutinyJsError { fn from(_: nostr::nips::nip19::Error) -> Self { Self::InvalidArgumentsError diff --git a/mutiny-wasm/src/lib.rs b/mutiny-wasm/src/lib.rs index 912d533ef..a27655517 100644 --- a/mutiny-wasm/src/lib.rs +++ b/mutiny-wasm/src/lib.rs @@ -16,15 +16,16 @@ use crate::error::MutinyJsError; use crate::indexed_db::IndexedDbStorage; use crate::models::*; use bip39::Mnemonic; +use bitcoin::bip32::ExtendedPrivKey; use bitcoin::consensus::deserialize; -use bitcoin::hashes::hex::{FromHex, ToHex}; +use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::sha256; use bitcoin::secp256k1::PublicKey; -use bitcoin::util::bip32::ExtendedPrivKey; use bitcoin::{Address, Network, OutPoint, Transaction, Txid}; use fedimint_core::{api::InviteCode, config::FederationId}; use futures::lock::Mutex; use gloo_utils::format::JsValueSerdeExt; +use hex_conservative::DisplayHex; use lightning::{log_error, log_info, log_warn, routing::gossip::NodeId, util::logger::Logger}; use lightning_invoice::Bolt11Invoice; use lnurl::lightning_address::LightningAddress; @@ -543,8 +544,7 @@ impl MutinyWallet { ) -> Result { // I know walia parses `pj=` and `pjos=` but payjoin::Uri parses the whole bip21 uri let pj_uri = payjoin::Uri::try_from(payjoin_uri.as_str()) - .map_err(|_| MutinyJsError::InvalidArgumentsError)? - .assume_checked(); + .map_err(|_| MutinyJsError::InvalidArgumentsError)?; Ok(self .inner .node_manager @@ -581,7 +581,7 @@ impl MutinyWallet { amount: u64, fee_rate: Option, ) -> Result { - let addr = Address::from_str(&destination_address)?; + let addr = Address::from_str(&destination_address)?.assume_checked(); Ok(self .inner .node_manager @@ -597,7 +597,7 @@ impl MutinyWallet { destination_address: String, fee_rate: Option, ) -> Result { - let addr = Address::from_str(&destination_address)?; + let addr = Address::from_str(&destination_address)?.assume_checked(); Ok(self .inner .node_manager @@ -669,7 +669,7 @@ impl MutinyWallet { ) -> Result */, MutinyJsError> { let address = Address::from_str(&address)?; Ok(JsValue::from_serde( - &self.inner.node_manager.check_address(&address).await?, + &self.inner.node_manager.check_address(address).await?, )?) } @@ -786,14 +786,15 @@ impl MutinyWallet { /// reconnect to the peer. #[wasm_bindgen] pub async fn delete_peer(&self, peer: String) -> Result<(), MutinyJsError> { - let peer = NodeId::from_str(&peer)?; + let peer = NodeId::from_str(&peer).map_err(|_| MutinyJsError::InvalidArgumentsError)?; Ok(self.inner.node_manager.delete_peer(None, &peer).await?) } /// Sets the label of a peer from the selected node. #[wasm_bindgen] pub fn label_peer(&self, node_id: String, label: Option) -> Result<(), MutinyJsError> { - let node_id = NodeId::from_str(&node_id)?; + let node_id = + NodeId::from_str(&node_id).map_err(|_| MutinyJsError::InvalidArgumentsError)?; self.inner.node_manager.label_peer(&node_id, label)?; Ok(()) } @@ -1194,7 +1195,7 @@ impl MutinyWallet { address: String, labels: Vec, ) -> Result<(), MutinyJsError> { - let address = Address::from_str(&address)?; + let address = Address::from_str(&address)?.assume_checked(); Ok(self .inner .node_manager @@ -1818,7 +1819,7 @@ impl MutinyWallet { #[wasm_bindgen] pub async fn npub_to_hexpub(npub: String) -> Result { let npub = parse_npub_or_nip05(&npub).await?; - Ok(npub.to_hex()) + Ok(npub.serialize().to_lower_hex_string()) } /// Convert an hex string to a npub string @@ -1832,8 +1833,7 @@ impl MutinyWallet { #[wasm_bindgen] pub async fn is_potential_hodl_invoice(invoice: String) -> Result { let invoice = Bolt11Invoice::from_str(&invoice)?; - Ok(mutiny_core::utils::HODL_INVOICE_NODES - .contains(&invoice.recover_payee_pub_key().to_hex().as_str())) + Ok(mutiny_core::utils::is_hodl_invoice(&invoice)) } } diff --git a/mutiny-wasm/src/models.rs b/mutiny-wasm/src/models.rs index a109b620b..e9ebb93fc 100644 --- a/mutiny-wasm/src/models.rs +++ b/mutiny-wasm/src/models.rs @@ -1,8 +1,8 @@ use ::nostr::ToBech32; -use bitcoin::hashes::hex::ToHex; -use bitcoin::secp256k1::PublicKey; +use bitcoin::secp256k1::{PublicKey, ThirtyTwoByteHash}; use bitcoin::OutPoint; use gloo_utils::format::JsValueSerdeExt; +use hex_conservative::DisplayHex; use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription}; use lnurl::lightning_address::LightningAddress; use lnurl::lnurl::LnUrl; @@ -74,11 +74,14 @@ impl From for ActivityItem { }; let id = match a { - mutiny_core::ActivityItem::OnChain(ref t) => t.txid.to_hex(), - mutiny_core::ActivityItem::Lightning(ref ln) => ln.payment_hash.to_hex(), - mutiny_core::ActivityItem::ChannelClosed(ref c) => { - c.user_channel_id.map(|c| c.to_hex()).unwrap_or_default() + mutiny_core::ActivityItem::OnChain(ref t) => t.txid.to_string(), + mutiny_core::ActivityItem::Lightning(ref ln) => { + ln.payment_hash.into_32().to_lower_hex_string() } + mutiny_core::ActivityItem::ChannelClosed(ref c) => c + .user_channel_id + .map(|c| c.to_lower_hex_string()) + .unwrap_or_default(), }; let (inbound, amount_sats) = match a { @@ -176,17 +179,15 @@ impl MutinyInvoice { impl From for MutinyInvoice { fn from(m: mutiny_core::MutinyInvoice) -> Self { let potential_hodl_invoice = match m.bolt11 { - Some(ref b) => { - utils::HODL_INVOICE_NODES.contains(&b.recover_payee_pub_key().to_hex().as_str()) - } + Some(ref b) => utils::is_hodl_invoice(b), None => false, }; MutinyInvoice { bolt11: m.bolt11, description: m.description, - payment_hash: m.payment_hash.to_hex(), + payment_hash: m.payment_hash.into_32().to_lower_hex_string(), preimage: m.preimage, - payee_pubkey: m.payee_pubkey.map(|p| p.to_hex()), + payee_pubkey: m.payee_pubkey.map(|p| p.serialize().to_lower_hex_string()), amount_sats: m.amount_sats, expire: m.expire, status: m.status.to_string(), @@ -202,7 +203,7 @@ impl From for MutinyInvoice { #[derive(Serialize, Deserialize, Clone, Eq, PartialEq)] #[wasm_bindgen] pub struct MutinyPeer { - pubkey: PublicKey, + pubkey: String, connection_string: Option, alias: Option, color: Option, @@ -219,7 +220,7 @@ impl MutinyPeer { #[wasm_bindgen(getter)] pub fn pubkey(&self) -> String { - self.pubkey.to_hex() + self.pubkey.clone() } #[wasm_bindgen(getter)] @@ -246,7 +247,7 @@ impl MutinyPeer { impl From for MutinyPeer { fn from(m: nodemanager::MutinyPeer) -> Self { MutinyPeer { - pubkey: m.pubkey, + pubkey: m.pubkey.serialize().to_lower_hex_string(), connection_string: m.connection_string, alias: m.alias, color: m.color, @@ -312,7 +313,7 @@ impl From for MutinyChannel { reserve: m.reserve, inbound: m.inbound, outpoint: m.outpoint.map(|o| o.to_string()), - peer: m.peer.to_hex(), + peer: m.peer.serialize().to_lower_hex_string(), confirmations_required: m.confirmations_required, confirmations: m.confirmations, is_outbound: m.is_outbound, @@ -345,8 +346,8 @@ impl From for nodemanager::MutinyChannel { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)] #[wasm_bindgen] pub struct ChannelClosure { - channel_id: Option<[u8; 32]>, - node_id: Option, + channel_id: Option, + node_id: Option, reason: String, pub timestamp: u64, } @@ -360,12 +361,12 @@ impl ChannelClosure { #[wasm_bindgen(getter)] pub fn channel_id(&self) -> Option { - self.channel_id.map(|c| c.to_hex()) + self.channel_id.clone() } #[wasm_bindgen(getter)] pub fn node_id(&self) -> Option { - self.node_id.map(|n| n.to_string()) + self.node_id.clone() } #[wasm_bindgen(getter)] @@ -389,8 +390,8 @@ impl Ord for ChannelClosure { impl From for ChannelClosure { fn from(c: nodemanager::ChannelClosure) -> Self { ChannelClosure { - channel_id: c.channel_id, - node_id: c.node_id, + channel_id: c.channel_id.map(|c| c.to_lower_hex_string()), + node_id: c.node_id.map(|c| c.serialize().to_lower_hex_string()), reason: c.reason, timestamp: c.timestamp, } @@ -1040,7 +1041,7 @@ impl From<(nostr::nwc::PendingNwcInvoice, Option)> for PendingNwcInvoice index: value.index, npub, invoice: value.invoice.to_string(), - id: value.invoice.payment_hash().to_hex(), + id: value.invoice.payment_hash().into_32().to_lower_hex_string(), amount_sats: value.invoice.amount_milli_satoshis().unwrap_or_default() / 1_000, invoice_description, profile_name, From bfca73f9d6817167ed18077f8458f34ce9edcedd Mon Sep 17 00:00:00 2001 From: benthecarman Date: Mon, 5 Feb 2024 14:28:58 +0000 Subject: [PATCH 2/2] Remove needed for passsword to get logs --- mutiny-core/src/logging.rs | 2 +- mutiny-wasm/src/indexed_db.rs | 26 ++++++++++++++++++++++++++ mutiny-wasm/src/lib.rs | 34 ++++++---------------------------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/mutiny-core/src/logging.rs b/mutiny-core/src/logging.rs index e00c0ab79..cf0b67c92 100644 --- a/mutiny-core/src/logging.rs +++ b/mutiny-core/src/logging.rs @@ -11,7 +11,7 @@ use hex_conservative::DisplayHex; use lightning::util::logger::{Level, Logger, Record}; use log::*; -pub(crate) const LOGGING_KEY: &str = "logs"; +pub const LOGGING_KEY: &str = "logs"; const MAX_LOG_ITEMS: usize = 10_000; diff --git a/mutiny-wasm/src/indexed_db.rs b/mutiny-wasm/src/indexed_db.rs index 149ce30f0..b94f6a23f 100644 --- a/mutiny-wasm/src/indexed_db.rs +++ b/mutiny-wasm/src/indexed_db.rs @@ -6,6 +6,7 @@ use gloo_utils::format::JsValueSerdeExt; use lightning::util::logger::Logger; use lightning::{log_debug, log_error, log_trace}; use log::error; +use mutiny_core::logging::LOGGING_KEY; use mutiny_core::storage::*; use mutiny_core::vss::*; use mutiny_core::*; @@ -140,6 +141,31 @@ impl IndexedDbStorage { Ok(res) } + pub(crate) async fn get_logs() -> Result>, MutinyError> { + let indexed_db = Self::build_indexed_db_database().await?; + let tx = indexed_db + .transaction(&[WALLET_OBJECT_STORE_NAME], TransactionMode::ReadOnly) + .map_err(|e| { + MutinyError::read_err( + anyhow!("Failed to create indexed db transaction: {e}").into(), + ) + })?; + + let store = tx.store(WALLET_OBJECT_STORE_NAME).map_err(|e| { + MutinyError::read_err(anyhow!("Failed to create indexed db store: {e}").into()) + })?; + + let key = JsValue::from(LOGGING_KEY); + let read = store + .get(&key) + .await + .map_err(|_| MutinyError::read_err(MutinyStorageError::IndexedDBError))?; + + let result: Option> = read.into_serde()?; + + Ok(result) + } + async fn save_to_indexed_db( indexed_db: &Arc>, items: &[(String, Value)], diff --git a/mutiny-wasm/src/lib.rs b/mutiny-wasm/src/lib.rs index a27655517..ab409022b 100644 --- a/mutiny-wasm/src/lib.rs +++ b/mutiny-wasm/src/lib.rs @@ -47,12 +47,9 @@ use mutiny_core::{ use mutiny_core::{logging::MutinyLogger, nostr::ProfileType}; use nostr::key::{FromSkStr, Secp256k1, SecretKey}; use nostr::{FromBech32, Keys, ToBech32}; +use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; -use std::{ - collections::HashMap, - sync::atomic::{AtomicBool, Ordering}, -}; use wasm_bindgen::prelude::*; static INITIALIZED: once_cell::sync::Lazy> = @@ -1356,26 +1353,9 @@ impl MutinyWallet { /// Exports the current state of the node manager to a json object. #[wasm_bindgen] - pub async fn get_logs( - password: Option, - ) -> Result> */, MutinyJsError> { - let logger = Arc::new(MutinyLogger::default()); - // TODO Password should not be required for logs - let cipher = password - .as_ref() - .filter(|p| !p.is_empty()) - .map(|p| encryption_key_from_pass(p)) - .transpose()?; - let storage = IndexedDbStorage::new(password, cipher, None, logger.clone()).await?; - let stop = Arc::new(AtomicBool::new(false)); - let logger = Arc::new(MutinyLogger::with_writer( - stop.clone(), - storage.clone(), - None, - )); - let res = JsValue::from_serde(&NodeManager::get_logs(storage, logger)?)?; - stop.swap(true, Ordering::Relaxed); - Ok(res) + pub async fn get_logs() -> Result> */, MutinyJsError> { + let logs = IndexedDbStorage::get_logs().await?; + Ok(JsValue::from_serde(&logs)?) } /// Get nostr wallet connect profiles @@ -2269,7 +2249,7 @@ mod tests { // sleep to make sure logs save sleep(6_000).await; - let logs = MutinyWallet::get_logs(None).await.expect("should get logs"); + let logs = MutinyWallet::get_logs().await.expect("should get logs"); let parsed_logs = js_to_option_vec_string(logs).expect("should parse logs"); assert!(parsed_logs.is_some()); assert!(!parsed_logs.clone().unwrap().is_empty()); @@ -2326,9 +2306,7 @@ mod tests { // sleep to make sure logs save sleep(6_000).await; - let logs = MutinyWallet::get_logs(password) - .await - .expect("should get logs"); + let logs = MutinyWallet::get_logs().await.expect("should get logs"); let parsed_logs = js_to_option_vec_string(logs).expect("should parse logs"); assert!(parsed_logs.is_some()); assert!(!parsed_logs.clone().unwrap().is_empty());