diff --git a/Cargo.lock b/Cargo.lock index c20c1197..bc396bf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "android_system_properties" @@ -26,25 +26,41 @@ dependencies = [ "libc", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", +] + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals", + "bitcoin_hashes", ] [[package]] @@ -61,21 +77,26 @@ checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b" [[package]] name = "bech32" -version = "0.9.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] name = "bitcoin" -version = "0.30.2" +version = "0.32.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" +checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" dependencies = [ - "bech32 0.9.1", - "bitcoin-private", + "base58ck", + "bech32 0.11.0", + "bitcoin-internals", + "bitcoin-io", + "bitcoin-units", "bitcoin_hashes", + "hex-conservative", "hex_lit", "secp256k1", + "serde", ] [[package]] @@ -88,148 +109,152 @@ dependencies = [ ] [[package]] -name = "bitcoin-private" -version = "0.1.0" +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73290177011694f38ec25e165d0387ab7ea749a4b81cd4c80dae5988229f7a57" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals", + "serde", +] [[package]] name = "bitcoin_hashes" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ - "bitcoin-private", + "bitcoin-io", + "hex-conservative", + "serde", ] [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytes" -version = "1.3.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.0.78" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +dependencies = [ + "find-msvc-tools", + "shlex", +] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", - "num-integer", "num-traits", - "winapi", + "serde", + "windows-link", ] [[package]] name = "chunked_transfer" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca491388666e04d7248af3f60f0c40cfb0991c72205595d7c396e3510207d1a" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "cxx" -version = "1.0.86" +name = "dnssec-prover" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", + "bitcoin_hashes", + "tokio", ] [[package]] -name = "cxx-build" -version = "1.0.86" +name = "find-msvc-tools" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.107", -] +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] -name = "cxxbridge-flags" -version = "1.0.86" +name = "fuchsia-cprng" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] -name = "cxxbridge-macro" -version = "1.0.86" +name = "getrandom" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", + "cfg-if", + "libc", + "wasi", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "gimli" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "gimli" -version = "0.28.1" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" @@ -239,40 +264,41 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", - "winapi", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -289,6 +315,7 @@ dependencies = [ "lightning", "lightning-background-processor", "lightning-block-sync", + "lightning-dns-resolver", "lightning-invoice", "lightning-net-tokio", "lightning-persister", @@ -300,62 +327,102 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.151" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] -name = "lightning" -version = "0.0.123" +name = "libm" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd92d4aa159374be430c7590e169b4a6c0fb79018f5bc4ea1bffde536384db3" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "lightning" +version = "0.2.0+git" dependencies = [ + "bech32 0.11.0", "bitcoin", - "hex-conservative", + "dnssec-prover", + "hashbrown", + "libm", + "lightning-invoice", + "lightning-macros", + "lightning-types", + "musig2", + "possiblyrandom", ] [[package]] name = "lightning-background-processor" -version = "0.0.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1c2c64050e37cee7c3b6b022106523784055ac3ee572d360780a1d6fe8062c" +version = "0.2.0+git" dependencies = [ "bitcoin", + "bitcoin-io", + "bitcoin_hashes", "lightning", + "lightning-liquidity", "lightning-rapid-gossip-sync", + "possiblyrandom", ] [[package]] name = "lightning-block-sync" -version = "0.0.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e1e70fa351daccede0c366cf16320b16a3e42b05ae3c7ec9c0df6b5d3a3e18" +version = "0.2.0+git" dependencies = [ "bitcoin", "chunked_transfer", - "hex-conservative", "lightning", "serde_json", "tokio", ] +[[package]] +name = "lightning-dns-resolver" +version = "0.3.0+git" +dependencies = [ + "dnssec-prover", + "lightning", + "lightning-types", + "tokio", +] + [[package]] name = "lightning-invoice" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d07d01cf197bf2184b929b7dc94aa70d935aac6df896c256a3a9475b7e9d40" +version = "0.34.0+git" dependencies = [ - "bech32 0.9.1", + "bech32 0.11.0", "bitcoin", + "lightning-types", + "serde", +] + +[[package]] +name = "lightning-liquidity" +version = "0.2.0+git" +dependencies = [ + "bitcoin", + "chrono", "lightning", - "secp256k1", + "lightning-invoice", + "lightning-macros", + "lightning-types", + "serde", + "serde_json", +] + +[[package]] +name = "lightning-macros" +version = "0.2.0+git" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "lightning-net-tokio" -version = "0.0.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e6a4d49c50a1344916d080dc8c012ce3a778cdd45de8def75350b2b40fe018" +version = "0.2.0+git" dependencies = [ "bitcoin", "lightning", @@ -364,93 +431,84 @@ dependencies = [ [[package]] name = "lightning-persister" -version = "0.0.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a8dd33971815fa074b05678e09a6d4b15c78225ea34d66ed4f17c35a53467a9" +version = "0.2.0+git" dependencies = [ "bitcoin", "lightning", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "lightning-rapid-gossip-sync" -version = "0.0.123" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d861b0f0cd5f8fe8c63760023c4fd4fd32c384881b41780b62ced2a8a619f91" +version = "0.2.0+git" dependencies = [ "bitcoin", + "bitcoin-io", + "bitcoin_hashes", "lightning", ] [[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +name = "lightning-types" +version = "0.3.0+git" dependencies = [ - "cc", + "bitcoin", ] [[package]] name = "log" -version = "0.4.17" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +name = "musig2" +version = "0.1.0" +source = "git+https://github.com/arik-so/rust-musig2?rev=6f95a05718cbb44d8fe3fa6021aea8117aa38d50#6f95a05718cbb44d8fe3fa6021aea8117aa38d50" dependencies = [ - "autocfg", - "num-traits", + "bitcoin", ] [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", @@ -458,39 +516,46 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "possiblyrandom" +version = "0.2.0" +dependencies = [ + "getrandom", +] [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -534,104 +599,117 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] -name = "ryu" -version = "1.0.12" +name = "rustversion" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "scratch" -version = "1.0.3" +name = "ryu" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes", "secp256k1-sys", + "serde", ] [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] [[package]] name = "serde" -version = "1.0.152" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", + "memchr", "ryu", "serde", + "serde_core", ] [[package]] -name = "socket2" -version = "0.5.5" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys", -] +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] -name = "syn" -version = "1.0.107" +name = "socket2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "libc", + "windows-sys 0.52.0", ] [[package]] name = "syn" -version = "2.0.47" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "tokio" -version = "1.35.1" +version = "1.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "68722da18b0fc4a05fdc1120b302b82051265792a1e1b399086e9b204b10ad3d" dependencies = [ "backtrace", "bytes", @@ -641,68 +719,64 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.47", + "syn", ] [[package]] name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-width" -version = "0.1.10" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", + "once_cell", + "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 1.0.107", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -710,22 +784,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] [[package]] name = "winapi" @@ -744,19 +821,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-util" -version = "0.1.5" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ - "winapi", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" +name = "windows-implement" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-result" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link", +] [[package]] name = "windows-sys" @@ -764,7 +891,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.6", ] [[package]] @@ -773,13 +909,29 @@ 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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -788,38 +940,86 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 20ebddb9..2a788107 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,15 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lightning = { version = "0.1.0", features = ["dnssec"] } -lightning-block-sync = { version = "0.1.0", features = [ "rpc-client", "tokio" ] } -lightning-dns-resolver = { version = "0.2.0" } -lightning-invoice = { version = "0.33.0" } -lightning-net-tokio = { version = "0.1.0" } -lightning-persister = { version = "0.1.0" } -lightning-background-processor = { version = "0.1.0", features = [ "futures" ] } -lightning-rapid-gossip-sync = { version = "0.1.0" } +lightning = { version = "0.2.0-beta1", features = ["dnssec"] } +lightning-block-sync = { version = "0.2.0-beta1", features = [ "rpc-client", "tokio" ] } +lightning-dns-resolver = { version = "0.3.0-beta1" } +lightning-invoice = { version = "0.34.0-beta1" } +lightning-net-tokio = { version = "0.2.0-beta1" } +lightning-persister = { version = "0.2.0-beta1", features = [ "tokio" ] } +lightning-background-processor = { version = "0.2.0-beta1" } +lightning-rapid-gossip-sync = { version = "0.2.0-beta1" } +lightning-macros = { version = "0.2.0-beta1" } base64 = "0.13.0" bitcoin = "0.32" @@ -26,7 +27,7 @@ libc = "0.2" chrono = { version = "0.4", default-features = false, features = ["clock"] } rand = "0.4" serde_json = { version = "1.0" } -tokio = { version = "1", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] } +tokio = { version = "1", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time", "io-std" ] } [profile.release] panic = "abort" diff --git a/src/bitcoind_client.rs b/src/bitcoind_client.rs index f16c5f41..01e2bed3 100644 --- a/src/bitcoind_client.rs +++ b/src/bitcoind_client.rs @@ -19,6 +19,7 @@ use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, use lightning::events::bump_transaction::{Utxo, WalletSource}; use lightning::log_error; use lightning::sign::ChangeDestinationSource; +use lightning::util::async_poll::AsyncResult; use lightning::util::logger::Logger; use lightning_block_sync::http::HttpEndpoint; use lightning_block_sync::rpc::RpcClient; @@ -31,7 +32,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; use std::time::Duration; -use tokio::runtime::{self, Runtime}; +use tokio::runtime::Handle; pub struct BitcoindClient { pub(crate) bitcoind_rpc_client: Arc, @@ -41,8 +42,7 @@ pub struct BitcoindClient { rpc_user: String, rpc_password: String, fees: Arc>, - main_runtime_handle: runtime::Handle, - inner_runtime: Arc, + main_runtime_handle: Handle, logger: Arc, } @@ -70,7 +70,7 @@ const MIN_FEERATE: u32 = 253; impl BitcoindClient { pub(crate) async fn new( host: String, port: u16, rpc_user: String, rpc_password: String, network: Network, - handle: runtime::Handle, logger: Arc, + handle: Handle, logger: Arc, ) -> std::io::Result { let http_endpoint = HttpEndpoint::for_host(host.clone()).with_port(port); let rpc_credentials = @@ -99,15 +99,6 @@ impl BitcoindClient { fees.insert(ConfirmationTarget::ChannelCloseMinimum, AtomicU32::new(MIN_FEERATE)); fees.insert(ConfirmationTarget::OutputSpendingFee, AtomicU32::new(MIN_FEERATE)); - let mut builder = runtime::Builder::new_multi_thread(); - let runtime = - builder.enable_all().worker_threads(1).thread_name("rpc-worker").build().unwrap(); - let inner_runtime = Arc::new(runtime); - // Tokio will panic if we drop a runtime while in another runtime. Because the entire - // application runs inside a tokio runtime, we have to ensure this runtime is never - // `drop`'d, which we do by leaking an Arc reference. - std::mem::forget(Arc::clone(&inner_runtime)); - let client = Self { bitcoind_rpc_client: Arc::new(bitcoind_rpc_client), host, @@ -117,7 +108,6 @@ impl BitcoindClient { network, fees: Arc::new(fees), main_runtime_handle: handle.clone(), - inner_runtime, logger, }; BitcoindClient::poll_for_fee_estimates( @@ -130,7 +120,7 @@ impl BitcoindClient { fn poll_for_fee_estimates( fees: Arc>, rpc_client: Arc, - handle: tokio::runtime::Handle, + handle: Handle, ) { handle.spawn(async move { loop { @@ -240,39 +230,6 @@ impl BitcoindClient { }); } - fn run_future_in_blocking_context(&self, future: F) -> F::Output - where - F::Output: Send + 'static, - { - // Tokio deliberately makes it nigh impossible to block on a future in a sync context that - // is running in an async task (which makes it really hard to interact with sync code that - // has callbacks in an async project). - // - // Reading the docs, it *seems* like - // `tokio::task::block_in_place(tokio::runtime::Handle::spawn(future))` should do the - // trick, and 99.999% of the time it does! But tokio has a "non-stealable I/O driver" - if - // the task we're running happens to, by sheer luck, be holding the "I/O driver" when we go - // into a `block_in_place` call, and the inner future requires I/O (which of course it - // does, its a future!), the whole thing will come to a grinding halt as no other thread is - // allowed to poll I/O until the blocked one finishes. - // - // This is, of course, nuts, and an almost trivial performance penalty of occasional - // additional wakeups would solve this, but tokio refuses to do so because any performance - // penalty at all would be too much (tokio issue #4730). - // - // Instead, we have to do a rather insane dance - we have to spawn the `future` we want to - // run on a *different* (threaded) tokio runtime (doing the `block_in_place` dance to avoid - // blocking too many threads on the main runtime). We want to block on that `future` being - // run on the other runtime's threads, but tokio only provides `block_on` to do so, which - // runs the `future` itself on the current thread, panicing if this thread is already a - // part of a tokio runtime (which in this case it is - the main tokio runtime). Thus, we - // have to `spawn` the `future` on the secondary runtime and then `block_on` the resulting - // `JoinHandle` on the main runtime. - tokio::task::block_in_place(move || { - self.main_runtime_handle.block_on(self.inner_runtime.spawn(future)).unwrap() - }) - } - pub fn get_new_rpc_client(&self) -> RpcClient { let http_endpoint = HttpEndpoint::for_host(self.host.clone()).with_port(self.port); let rpc_credentials = base64::encode(format!("{}:{}", self.rpc_user, self.rpc_password)); @@ -406,59 +363,63 @@ impl BroadcasterInterface for BitcoindClient { } impl ChangeDestinationSource for BitcoindClient { - fn get_change_destination_script(&self) -> Result { - let future = self.get_new_address(); - Ok(self.run_future_in_blocking_context(async move { future.await.script_pubkey() })) + fn get_change_destination_script<'a>(&'a self) -> AsyncResult<'a, ScriptBuf> { + Box::pin(async move { + Ok(self.get_new_address().await.script_pubkey()) + }) } } impl WalletSource for BitcoindClient { - fn list_confirmed_utxos(&self) -> Result, ()> { - let future = self.list_unspent(); - let utxos = self.run_future_in_blocking_context(async move { future.await.0 }); - Ok(utxos - .into_iter() - .filter_map(|utxo| { - let outpoint = OutPoint { txid: utxo.txid, vout: utxo.vout }; - let value = bitcoin::Amount::from_sat(utxo.amount); - match utxo.address.witness_program() { - Some(prog) if prog.is_p2wpkh() => { - WPubkeyHash::from_slice(prog.program().as_bytes()) - .map(|wpkh| Utxo::new_v0_p2wpkh(outpoint, value, &wpkh)) - .ok() - }, - Some(prog) if prog.is_p2tr() => { - // TODO: Add `Utxo::new_v1_p2tr` upstream. - XOnlyPublicKey::from_slice(prog.program().as_bytes()) - .map(|_| Utxo { - outpoint, - output: TxOut { - value, - script_pubkey: utxo.address.script_pubkey(), - }, - satisfaction_weight: 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64 + - 1 /* witness items */ + 1 /* schnorr sig len */ + 64, /* schnorr sig */ - }) - .ok() - }, - _ => None, - } - }) - .collect()) + fn list_confirmed_utxos<'a>(&'a self) -> AsyncResult<'a, Vec> { + Box::pin(async move { + let utxos = self.list_unspent().await.0; + Ok(utxos + .into_iter() + .filter_map(|utxo| { + let outpoint = OutPoint { txid: utxo.txid, vout: utxo.vout }; + let value = bitcoin::Amount::from_sat(utxo.amount); + match utxo.address.witness_program() { + Some(prog) if prog.is_p2wpkh() => { + WPubkeyHash::from_slice(prog.program().as_bytes()) + .map(|wpkh| Utxo::new_v0_p2wpkh(outpoint, value, &wpkh)) + .ok() + }, + Some(prog) if prog.is_p2tr() => { + // TODO: Add `Utxo::new_v1_p2tr` upstream. + XOnlyPublicKey::from_slice(prog.program().as_bytes()) + .map(|_| Utxo { + outpoint, + output: TxOut { + value, + script_pubkey: utxo.address.script_pubkey(), + }, + satisfaction_weight: 1 /* empty script_sig */ * WITNESS_SCALE_FACTOR as u64 + + 1 /* witness items */ + 1 /* schnorr sig len */ + 64, /* schnorr sig */ + }) + .ok() + }, + _ => None, + } + }) + .collect()) + }) } - fn get_change_script(&self) -> Result { - let future = self.get_new_address(); - Ok(self.run_future_in_blocking_context(async move { future.await.script_pubkey() })) + fn get_change_script<'a>(&'a self) -> AsyncResult<'a, ScriptBuf> { + Box::pin(async move { + Ok(self.get_new_address().await.script_pubkey()) + }) } - fn sign_psbt(&self, tx: Psbt) -> Result { - let mut tx_bytes = Vec::new(); - let _ = tx.unsigned_tx.consensus_encode(&mut tx_bytes).map_err(|_| ()); - let tx_hex = hex_utils::hex_str(&tx_bytes); - let future = self.sign_raw_transaction_with_wallet(tx_hex); - let signed_tx = self.run_future_in_blocking_context(async move { future.await }); - let signed_tx_bytes = hex_utils::to_vec(&signed_tx.hex).ok_or(())?; - Transaction::consensus_decode(&mut signed_tx_bytes.as_slice()).map_err(|_| ()) + fn sign_psbt<'a>(&'a self, tx: Psbt) -> AsyncResult<'a, Transaction> { + Box::pin(async move { + let mut tx_bytes = Vec::new(); + let _ = tx.unsigned_tx.consensus_encode(&mut tx_bytes).map_err(|_| ()); + let tx_hex = hex_utils::hex_str(&tx_bytes); + let signed_tx = self.sign_raw_transaction_with_wallet(tx_hex).await; + let signed_tx_bytes = hex_utils::to_vec(&signed_tx.hex).ok_or(())?; + Transaction::consensus_decode(&mut signed_tx_bytes.as_slice()).map_err(|_| ()) + }) } } diff --git a/src/cli.rs b/src/cli.rs index 528cc73f..e1affd55 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME}; +use crate::disk::{INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME}; use crate::hex_utils; use crate::{ ChainMonitor, ChannelManager, HTLCStatus, InboundPaymentInfoStorage, MillisatAmount, @@ -9,10 +9,8 @@ use bitcoin::hashes::Hash; use bitcoin::network::Network; use bitcoin::secp256k1::PublicKey; use lightning::chain::channelmonitor::Balance; -use lightning::ln::bolt11_payment::payment_parameters_from_invoice; -use lightning::ln::bolt11_payment::payment_parameters_from_variable_amount_invoice; use lightning::ln::channelmanager::{ - Bolt11InvoiceParameters, PaymentId, RecipientOnionFields, Retry, + Bolt11InvoiceParameters, OptionalOfferPaymentParams, PaymentId, RecipientOnionFields, Retry, }; use lightning::ln::msgs::SocketAddress; use lightning::ln::types::ChannelId; @@ -20,7 +18,7 @@ use lightning::offers::offer::{self, Offer}; use lightning::onion_message::dns_resolution::HumanReadableName; use lightning::onion_message::messenger::Destination; use lightning::routing::gossip::NodeId; -use lightning::routing::router::{PaymentParameters, RouteParameters}; +use lightning::routing::router::{PaymentParameters, RouteParameters, RouteParametersConfig}; use lightning::sign::{EntropySource, KeysManager}; use lightning::types::payment::{PaymentHash, PaymentPreimage}; use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig}; @@ -31,11 +29,12 @@ use lightning_persister::fs_store::FilesystemStore; use std::env; use std::io::Write; use std::net::{SocketAddr, ToSocketAddrs}; -use std::path::Path; use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::time::Duration; +use tokio::io::{AsyncBufReadExt, BufReader}; + pub(crate) struct LdkUserInfo { pub(crate) bitcoind_rpc_username: String, pub(crate) bitcoind_rpc_password: String, @@ -48,30 +47,31 @@ pub(crate) struct LdkUserInfo { pub(crate) network: Network, } -pub(crate) fn poll_for_user_input( +pub(crate) async fn poll_for_user_input( peer_manager: Arc, channel_manager: Arc, chain_monitor: Arc, keys_manager: Arc, network_graph: Arc, inbound_payments: Arc>, - outbound_payments: Arc>, ldk_data_dir: String, - fs_store: Arc, + outbound_payments: Arc>, fs_store: Arc, ) { println!( "LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit." ); println!("LDK logs are available at /.ldk/logs"); println!("Local Node ID is {}.", channel_manager.get_our_node_id()); + + let mut input = BufReader::new(tokio::io::stdin()).lines(); 'read_command: loop { print!("> "); std::io::stdout().flush().unwrap(); // Without flushing, the `>` doesn't print - let mut line = String::new(); - if let Err(e) = std::io::stdin().read_line(&mut line) { - break println!("ERROR: {}", e); - } - - if line.len() == 0 { - // We hit EOF / Ctrl-D - break; - } + let line = match input.next_line().await { + Ok(Some(l)) => l, + Err(e) => { + break println!("ERROR: {}", e); + }, + Ok(None) => { + break println!("ERROR: End of stdin"); + }, + }; let mut words = line.split_whitespace(); if let Some(word) = words.next() { @@ -111,12 +111,12 @@ pub(crate) fn poll_for_user_input( }, }; - if tokio::runtime::Handle::current() - .block_on(connect_peer_if_necessary( - pubkey, - peer_addr, - peer_manager.clone(), - )) + if connect_peer_if_necessary( + pubkey, + peer_addr, + peer_manager.clone(), + ) + .await .is_err() { continue; @@ -142,24 +142,13 @@ pub(crate) fn poll_for_user_input( } } - if open_channel( + let _ = open_channel( pubkey, chan_amt_sat.unwrap(), announce_channel, with_anchors, channel_manager.clone(), - ) - .is_ok() - { - if peer_addr_str.is_some() { - let peer_data_path = - format!("{}/channel_peer_data", ldk_data_dir.clone()); - let _ = disk::persist_channel_peer( - Path::new(&peer_data_path), - peer_pubkey_and_ip_addr, - ); - } - } + ); }, "sendpayment" => { let invoice_str = words.next(); @@ -201,15 +190,17 @@ pub(crate) fn poll_for_user_input( print!("Paying offer for {} msat. Continue (Y/N)? >", amt_msat); std::io::stdout().flush().unwrap(); - if let Err(e) = std::io::stdin().read_line(&mut line) { - println!("ERROR: {}", e); - break 'read_command; - } - - if line.len() == 0 { - // We hit EOF / Ctrl-D - break 'read_command; - } + let line = match input.next_line().await { + Ok(Some(l)) => l, + Err(e) => { + println!("ERROR: {}", e); + break 'read_command; + }, + Ok(None) => { + println!("ERROR: End of stdin"); + break 'read_command; + }, + }; if line.starts_with("Y") { break; @@ -229,13 +220,16 @@ pub(crate) fn poll_for_user_input( }, ); fs_store - .write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()) + .write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + .await .unwrap(); - let retry = Retry::Timeout(Duration::from_secs(10)); + let params = OptionalOfferPaymentParams { + retry_strategy: Retry::Timeout(Duration::from_secs(10)), + ..Default::default() + }; let amt = Some(amt_msat); - let pay = channel_manager - .pay_for_offer(&offer, None, amt, None, payment_id, retry, None); + let pay = channel_manager.pay_for_offer(&offer, amt, payment_id, params); if pay.is_ok() { println!("Payment in flight"); } else { @@ -292,14 +286,18 @@ pub(crate) fn poll_for_user_input( }, ); fs_store - .write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()) + .write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + .await .unwrap(); - let retry = Retry::Timeout(Duration::from_secs(10)); - let pay = |a, b, c, d, e, f| { - channel_manager.pay_for_offer_from_human_readable_name(a, b, c, d, e, f) + let params = OptionalOfferPaymentParams { + retry_strategy: Retry::Timeout(Duration::from_secs(10)), + ..Default::default() }; - let pay = pay(hrn, amt_msat, payment_id, retry, None, dns_resolvers); + let pay = |a, b, c, d, e| { + channel_manager.pay_for_offer_from_human_readable_name(a, b, c, d, e) + }; + let pay = pay(hrn, amt_msat, payment_id, params, dns_resolvers); if pay.is_ok() { println!("Payment in flight"); } else { @@ -311,9 +309,9 @@ pub(crate) fn poll_for_user_input( &channel_manager, &invoice, user_provided_amt, - &mut outbound_payments.lock().unwrap(), - Arc::clone(&fs_store), - ), + &outbound_payments, + &*fs_store, + ).await, Err(e) => { println!("ERROR: invalid invoice: {:?}", e); }, @@ -353,12 +351,12 @@ pub(crate) fn poll_for_user_input( dest_pubkey, amt_msat, &*keys_manager, - &mut outbound_payments.lock().unwrap(), - Arc::clone(&fs_store), - ); + &outbound_payments, + &*fs_store, + ).await; }, "getoffer" => { - let offer_builder = channel_manager.create_offer_builder(None); + let offer_builder = channel_manager.create_offer_builder(); if let Err(e) = offer_builder { println!("ERROR: Failed to initiate offer building: {:?}", e); continue; @@ -410,16 +408,18 @@ pub(crate) fn poll_for_user_input( continue; } - let mut inbound_payments = inbound_payments.lock().unwrap(); - get_invoice( - amt_msat.unwrap(), - &mut inbound_payments, - &channel_manager, - expiry_secs.unwrap(), - ); - fs_store - .write("", "", INBOUND_PAYMENTS_FNAME, &inbound_payments.encode()) - .unwrap(); + let write_future = { + let mut inbound_payments = inbound_payments.lock().unwrap(); + get_invoice( + amt_msat.unwrap(), + &mut inbound_payments, + &channel_manager, + expiry_secs.unwrap(), + ); + fs_store + .write("", "", INBOUND_PAYMENTS_FNAME, inbound_payments.encode()) + }; + write_future.await.unwrap(); }, "connectpeer" => { let peer_pubkey_and_ip_addr = words.next(); @@ -435,12 +435,12 @@ pub(crate) fn poll_for_user_input( continue; }, }; - if tokio::runtime::Handle::current() - .block_on(connect_peer_if_necessary( - pubkey, - peer_addr, - peer_manager.clone(), - )) + if connect_peer_if_necessary( + pubkey, + peer_addr, + peer_manager.clone(), + ) + .await .is_ok() { println!("SUCCESS: connected to peer {}", pubkey); @@ -618,8 +618,12 @@ fn node_info( let local_balance_sat = balances.iter().map(|b| b.claimable_amount_satoshis()).sum::(); println!("\t\t local_balance_sats: {}", local_balance_sat); let close_fees_map = |b| match b { - &Balance::ClaimableOnChannelClose { transaction_fee_satoshis, .. } => { - transaction_fee_satoshis + &Balance::ClaimableOnChannelClose { + ref balance_candidates, + confirmed_balance_candidate_index, + .. + } => { + balance_candidates[confirmed_balance_candidate_index].transaction_fee_satoshis }, _ => 0, }; @@ -738,10 +742,8 @@ fn list_payments( pub(crate) async fn connect_peer_if_necessary( pubkey: PublicKey, peer_addr: SocketAddr, peer_manager: Arc, ) -> Result<(), ()> { - for peer_details in peer_manager.list_peers() { - if peer_details.counterparty_node_id == pubkey { - return Ok(()); - } + if peer_manager.peer_by_node_id(&pubkey).is_some() { + return Ok(()); } let res = do_connect_peer(pubkey, peer_addr, peer_manager).await; if res.is_err() { @@ -823,78 +825,75 @@ fn open_channel( } } -fn send_payment( +async fn send_payment( channel_manager: &ChannelManager, invoice: &Bolt11Invoice, required_amount_msat: Option, - outbound_payments: &mut OutboundPaymentInfoStorage, fs_store: Arc, + outbound_payments: &Mutex, fs_store: &FilesystemStore, ) { let payment_id = PaymentId((*invoice.payment_hash()).to_byte_array()); let payment_secret = Some(*invoice.payment_secret()); - let zero_amt_invoice = - invoice.amount_milli_satoshis().is_none() || invoice.amount_milli_satoshis() == Some(0); - let pay_params_opt = if zero_amt_invoice { - if let Some(amt_msat) = required_amount_msat { - payment_parameters_from_variable_amount_invoice(invoice, amt_msat) - } else { - println!("Need an amount for the given 0-value invoice"); - print!("> "); - return; - } - } else { - if required_amount_msat.is_some() && invoice.amount_milli_satoshis() != required_amount_msat - { + let amt_msat = match (invoice.amount_milli_satoshis(), required_amount_msat) { + // pay_for_bolt11_invoice only validates that the amount we pay is >= the invoice's + // required amount, not that its equal (to allow for overpayment). As that is somewhat + // surprising, here we check and reject all disagreements in amount. + (Some(inv_amt), Some(req_amt)) if inv_amt != req_amt => { println!( "Amount didn't match invoice value of {}msat", invoice.amount_milli_satoshis().unwrap_or(0) ); print!("> "); return; - } - payment_parameters_from_invoice(invoice) - }; - let (payment_hash, recipient_onion, route_params) = match pay_params_opt { - Ok(res) => res, - Err(e) => { - println!("Failed to parse invoice: {:?}", e); + }, + (Some(inv_amt), _) => inv_amt, + (_, Some(req_amt)) => req_amt, + (None, None) => { + println!("Need an amount to pay an amountless invoice"); print!("> "); return; }, }; - outbound_payments.payments.insert( - payment_id, - PaymentInfo { - preimage: None, - secret: payment_secret, - status: HTLCStatus::Pending, - amt_msat: MillisatAmount(invoice.amount_milli_satoshis()), - }, - ); - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); + let write_future = { + let mut outbound_payments = outbound_payments.lock().unwrap(); + outbound_payments.payments.insert( + payment_id, + PaymentInfo { + preimage: None, + secret: payment_secret, + status: HTLCStatus::Pending, + amt_msat: MillisatAmount(Some(amt_msat)), + }, + ); + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + }; + write_future.await.unwrap(); - match channel_manager.send_payment( - payment_hash, - recipient_onion, + match channel_manager.pay_for_bolt11_invoice( + invoice, payment_id, - route_params, + required_amount_msat, + RouteParametersConfig::default(), Retry::Timeout(Duration::from_secs(10)), ) { Ok(_) => { let payee_pubkey = invoice.recover_payee_pub_key(); - let amt_msat = invoice.amount_milli_satoshis().unwrap(); println!("EVENT: initiated sending {} msats to {}", amt_msat, payee_pubkey); print!("> "); }, Err(e) => { println!("ERROR: failed to send payment: {:?}", e); print!("> "); - outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); + let write_future = { + let mut outbound_payments = outbound_payments.lock().unwrap(); + outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + }; + write_future.await.unwrap(); }, }; } -fn keysend( +async fn keysend( channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E, - outbound_payments: &mut OutboundPaymentInfoStorage, fs_store: Arc, + outbound_payments: &Mutex, fs_store: &FilesystemStore, ) { let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes()); let payment_id = PaymentId(Sha256::hash(&payment_preimage.0[..]).to_byte_array()); @@ -903,16 +902,20 @@ fn keysend( PaymentParameters::for_keysend(payee_pubkey, 40, false), amt_msat, ); - outbound_payments.payments.insert( - payment_id, - PaymentInfo { - preimage: None, - secret: None, - status: HTLCStatus::Pending, - amt_msat: MillisatAmount(Some(amt_msat)), - }, - ); - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); + let write_future = { + let mut outbound_payments = outbound_payments.lock().unwrap(); + outbound_payments.payments.insert( + payment_id, + PaymentInfo { + preimage: None, + secret: None, + status: HTLCStatus::Pending, + amt_msat: MillisatAmount(Some(amt_msat)), + }, + ); + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + }; + write_future.await.unwrap(); match channel_manager.send_spontaneous_payment( Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), @@ -927,8 +930,12 @@ fn keysend( Err(e) => { println!("ERROR: failed to send payment: {:?}", e); print!("> "); - outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); + let write_future = { + let mut outbound_payments = outbound_payments.lock().unwrap(); + outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.encode()) + }; + write_future.await.unwrap(); }, }; } diff --git a/src/disk.rs b/src/disk.rs index 00f0ea4d..19a77584 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -1,15 +1,13 @@ -use crate::{cli, InboundPaymentInfoStorage, NetworkGraph, OutboundPaymentInfoStorage}; -use bitcoin::secp256k1::PublicKey; +use crate::{InboundPaymentInfoStorage, NetworkGraph, OutboundPaymentInfoStorage}; use bitcoin::Network; use chrono::Utc; use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringDecayParameters}; -use lightning::util::hash_tables::{new_hash_map, HashMap}; +use lightning::util::hash_tables::new_hash_map; use lightning::util::logger::{Level, Logger, Record}; use lightning::util::ser::{Readable, ReadableArgs}; use std::fs; use std::fs::File; -use std::io::{BufRead, BufReader, Write}; -use std::net::SocketAddr; +use std::io::{BufReader, Write}; use std::path::Path; use std::sync::Arc; @@ -54,30 +52,6 @@ impl Logger for FilesystemLogger { .unwrap(); } } -pub(crate) fn persist_channel_peer(path: &Path, peer_info: &str) -> std::io::Result<()> { - let mut file = fs::OpenOptions::new().create(true).append(true).open(path)?; - file.write_all(format!("{}\n", peer_info).as_bytes()) -} - -pub(crate) fn read_channel_peer_data( - path: &Path, -) -> Result, std::io::Error> { - let mut peer_data = new_hash_map(); - if !Path::new(&path).exists() { - return Ok(new_hash_map()); - } - let file = File::open(path)?; - let reader = BufReader::new(file); - for line in reader.lines() { - match cli::parse_peer_info(line.unwrap()) { - Ok((pubkey, socket_addr)) => { - peer_data.insert(pubkey, socket_addr); - }, - Err(e) => return Err(e), - } - } - Ok(peer_data) -} pub(crate) fn read_network( path: &Path, network: Network, logger: Arc, diff --git a/src/main.rs b/src/main.rs index 370838da..83c10efa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,19 +35,20 @@ use lightning::routing::gossip; use lightning::routing::gossip::{NodeId, P2PGossipSync}; use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::ProbabilisticScoringFeeParameters; -use lightning::sign::{EntropySource, InMemorySigner, KeysManager}; +use lightning::sign::{EntropySource, InMemorySigner, KeysManager, NodeSigner}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::UserConfig; use lightning::util::hash_tables::hash_map::Entry; use lightning::util::hash_tables::HashMap; +use lightning::util::native_async::FutureSpawner; use lightning::util::persist::{ - self, KVStore, MonitorUpdatingPersister, OUTPUT_SWEEPER_PERSISTENCE_KEY, + self, KVStore, MonitorUpdatingPersisterAsync, OUTPUT_SWEEPER_PERSISTENCE_KEY, OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, }; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use lightning::util::sweep as ldk_sweep; use lightning::{chain, impl_writeable_tlv_based, impl_writeable_tlv_based_enum}; -use lightning_background_processor::{process_events_async, GossipSync}; +use lightning_background_processor::{process_events_async, GossipSync, NO_LIQUIDITY_MANAGER}; use lightning_block_sync::init; use lightning_block_sync::poll; use lightning_block_sync::SpvClient; @@ -61,6 +62,7 @@ use std::convert::TryInto; use std::fmt; use std::fs; use std::fs::File; +use std::future::Future; use std::io::{BufReader, Write}; use std::net::ToSocketAddrs; use std::path::Path; @@ -141,16 +143,16 @@ type ChainMonitor = chainmonitor::ChainMonitor< Arc, Arc, Arc, - Arc< - MonitorUpdatingPersister< - Arc, - Arc, - Arc, - Arc, - Arc, - Arc, - >, + chainmonitor::AsyncPersister< + Arc, + TokioSpawner, + Arc, + Arc, + Arc, + Arc, + Arc, >, + Arc, >; pub(crate) type GossipVerifier = lightning_block_sync::gossip::GossipVerifier< @@ -169,6 +171,7 @@ pub(crate) type PeerManager = LdkPeerManager< Arc, IgnoringMessageHandler, Arc, + Arc, >; pub(crate) type ChannelManager = @@ -210,339 +213,350 @@ pub(crate) type OutputSweeper = ldk_sweep::OutputSweeper< // Needed due to rust-lang/rust#63033. struct OutputSweeperWrapper(Arc); -async fn handle_ldk_events( - channel_manager: Arc, bitcoind_client: &BitcoindClient, - network_graph: &NetworkGraph, keys_manager: &KeysManager, - bump_tx_event_handler: &BumpTxEventHandler, peer_manager: Arc, +// Trivially bridge the LDK FutureSpawner trait to tokio +struct TokioSpawner; +impl FutureSpawner for TokioSpawner{ + fn spawn + Send + 'static>(&self, future: T) { + tokio::spawn(future); + } +} + +fn handle_ldk_events<'a>( + channel_manager: Arc, bitcoind_client: &'a BitcoindClient, + network_graph: &'a NetworkGraph, keys_manager: &'a KeysManager, + bump_tx_event_handler: &'a BumpTxEventHandler, peer_manager: Arc, inbound_payments: Arc>, outbound_payments: Arc>, fs_store: Arc, output_sweeper: OutputSweeperWrapper, network: Network, event: Event, -) { - match event { - Event::FundingGenerationReady { - temporary_channel_id, - counterparty_node_id, - channel_value_satoshis, - output_script, - .. - } => { - // Construct the raw transaction with one output, that is paid the amount of the - // channel. - let addr = WitnessProgram::from_scriptpubkey( - &output_script.as_bytes(), - match network { - Network::Bitcoin => bitcoin_bech32::constants::Network::Bitcoin, - Network::Regtest => bitcoin_bech32::constants::Network::Regtest, - Network::Signet => bitcoin_bech32::constants::Network::Signet, - Network::Testnet | _ => bitcoin_bech32::constants::Network::Testnet, - }, - ) - .expect("Lightning funding tx should always be to a SegWit output") - .to_address(); - let mut outputs = vec![StdHashMap::new()]; - outputs[0].insert(addr, channel_value_satoshis as f64 / 100_000_000.0); - let raw_tx = bitcoind_client.create_raw_transaction(outputs).await; - - // Have your wallet put the inputs into the transaction such that the output is - // satisfied. - let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx).await; - - // Sign the final funding transaction and give it to LDK, who will eventually broadcast it. - let signed_tx = bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex).await; - assert_eq!(signed_tx.complete, true); - let final_tx: Transaction = - encode::deserialize(&hex_utils::to_vec(&signed_tx.hex).unwrap()).unwrap(); - // Give the funding transaction back to LDK for opening the channel. - if channel_manager - .funding_transaction_generated(temporary_channel_id, counterparty_node_id, final_tx) - .is_err() - { - println!( - "\nERROR: Channel went away before we could fund it. The peer disconnected or refused the channel."); - print!("> "); - std::io::stdout().flush().unwrap(); - } - }, - Event::FundingTxBroadcastSafe { .. } => { - // We don't use the manual broadcasting feature, so this event should never be seen. - }, - Event::PaymentClaimable { payment_hash, purpose, amount_msat, .. } => { - println!( - "\nEVENT: received payment from payment hash {} of {} millisatoshis", - payment_hash, amount_msat, - ); - print!("> "); - std::io::stdout().flush().unwrap(); - let payment_preimage = match purpose { - PaymentPurpose::Bolt11InvoicePayment { payment_preimage, .. } => payment_preimage, - PaymentPurpose::Bolt12OfferPayment { payment_preimage, .. } => payment_preimage, - PaymentPurpose::Bolt12RefundPayment { payment_preimage, .. } => payment_preimage, - PaymentPurpose::SpontaneousPayment(preimage) => Some(preimage), - }; - channel_manager.claim_funds(payment_preimage.unwrap()); - }, - Event::PaymentClaimed { payment_hash, purpose, amount_msat, .. } => { - println!( - "\nEVENT: claimed payment from payment hash {} of {} millisatoshis", - payment_hash, amount_msat, - ); - print!("> "); - std::io::stdout().flush().unwrap(); - let (payment_preimage, payment_secret) = match purpose { - PaymentPurpose::Bolt11InvoicePayment { - payment_preimage, payment_secret, .. - } => (payment_preimage, Some(payment_secret)), - PaymentPurpose::Bolt12OfferPayment { payment_preimage, payment_secret, .. } => { - (payment_preimage, Some(payment_secret)) - }, - PaymentPurpose::Bolt12RefundPayment { - payment_preimage, payment_secret, .. - } => (payment_preimage, Some(payment_secret)), - PaymentPurpose::SpontaneousPayment(preimage) => (Some(preimage), None), - }; - let mut inbound = inbound_payments.lock().unwrap(); - match inbound.payments.entry(payment_hash) { - Entry::Occupied(mut e) => { - let payment = e.get_mut(); - payment.status = HTLCStatus::Succeeded; - payment.preimage = payment_preimage; - payment.secret = payment_secret; - }, - Entry::Vacant(e) => { - e.insert(PaymentInfo { - preimage: payment_preimage, - secret: payment_secret, - status: HTLCStatus::Succeeded, - amt_msat: MillisatAmount(Some(amount_msat)), - }); - }, - } - fs_store.write("", "", INBOUND_PAYMENTS_FNAME, &inbound.encode()).unwrap(); - }, - Event::PaymentSent { - payment_preimage, payment_hash, fee_paid_msat, payment_id, .. - } => { - let mut outbound = outbound_payments.lock().unwrap(); - for (id, payment) in outbound.payments.iter_mut() { - if *id == payment_id.unwrap() { - payment.preimage = Some(payment_preimage); - payment.status = HTLCStatus::Succeeded; +) -> impl core::future::Future + 'a { + async move { + match event { + Event::FundingGenerationReady { + temporary_channel_id, + counterparty_node_id, + channel_value_satoshis, + output_script, + .. + } => { + // Construct the raw transaction with one output, that is paid the amount of the + // channel. + let addr = WitnessProgram::from_scriptpubkey( + &output_script.as_bytes(), + match network { + Network::Bitcoin => bitcoin_bech32::constants::Network::Bitcoin, + Network::Regtest => bitcoin_bech32::constants::Network::Regtest, + Network::Signet => bitcoin_bech32::constants::Network::Signet, + Network::Testnet | _ => bitcoin_bech32::constants::Network::Testnet, + }, + ) + .expect("Lightning funding tx should always be to a SegWit output") + .to_address(); + let mut outputs = vec![StdHashMap::new()]; + outputs[0].insert(addr, channel_value_satoshis as f64 / 100_000_000.0); + let raw_tx = bitcoind_client.create_raw_transaction(outputs).await; + + // Have your wallet put the inputs into the transaction such that the output is + // satisfied. + let funded_tx = bitcoind_client.fund_raw_transaction(raw_tx).await; + + // Sign the final funding transaction and give it to LDK, who will eventually broadcast it. + let signed_tx = bitcoind_client.sign_raw_transaction_with_wallet(funded_tx.hex).await; + assert_eq!(signed_tx.complete, true); + let final_tx: Transaction = + encode::deserialize(&hex_utils::to_vec(&signed_tx.hex).unwrap()).unwrap(); + // Give the funding transaction back to LDK for opening the channel. + if channel_manager + .funding_transaction_generated(temporary_channel_id, counterparty_node_id, final_tx) + .is_err() + { println!( - "\nEVENT: successfully sent payment of {} millisatoshis{} from \ - payment hash {} with preimage {}", - payment.amt_msat, - if let Some(fee) = fee_paid_msat { - format!(" (fee {} msat)", fee) - } else { - "".to_string() - }, - payment_hash, - payment_preimage - ); + "\nERROR: Channel went away before we could fund it. The peer disconnected or refused the channel."); print!("> "); std::io::stdout().flush().unwrap(); } - } - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); - }, - Event::OpenChannelRequest { - ref temporary_channel_id, ref counterparty_node_id, .. - } => { - let mut random_bytes = [0u8; 16]; - random_bytes.copy_from_slice(&keys_manager.get_secure_random_bytes()[..16]); - let user_channel_id = u128::from_be_bytes(random_bytes); - let res = channel_manager.accept_inbound_channel( - temporary_channel_id, - counterparty_node_id, - user_channel_id, - ); - - if let Err(e) = res { - print!( - "\nEVENT: Failed to accept inbound channel ({}) from {}: {:?}", - temporary_channel_id, - hex_utils::hex_str(&counterparty_node_id.serialize()), - e, - ); - } else { - print!( - "\nEVENT: Accepted inbound channel ({}) from {}", - temporary_channel_id, - hex_utils::hex_str(&counterparty_node_id.serialize()), + }, + Event::FundingTxBroadcastSafe { .. } => { + // We don't use the manual broadcasting feature, so this event should never be seen. + }, + Event::PaymentClaimable { payment_hash, purpose, amount_msat, .. } => { + println!( + "\nEVENT: received payment from payment hash {} of {} millisatoshis", + payment_hash, amount_msat, ); - } - print!("> "); - std::io::stdout().flush().unwrap(); - }, - Event::PaymentPathSuccessful { .. } => {}, - Event::PaymentPathFailed { .. } => {}, - Event::ProbeSuccessful { .. } => {}, - Event::ProbeFailed { .. } => {}, - Event::PaymentFailed { payment_hash, reason, payment_id, .. } => { - if let Some(hash) = payment_hash { - print!( - "\nEVENT: Failed to send payment to payment ID {}, payment hash {}: {:?}", - payment_id, - hash, - if let Some(r) = reason { r } else { PaymentFailureReason::RetriesExhausted } + print!("> "); + std::io::stdout().flush().unwrap(); + let payment_preimage = match purpose { + PaymentPurpose::Bolt11InvoicePayment { payment_preimage, .. } => payment_preimage, + PaymentPurpose::Bolt12OfferPayment { payment_preimage, .. } => payment_preimage, + PaymentPurpose::Bolt12RefundPayment { payment_preimage, .. } => payment_preimage, + PaymentPurpose::SpontaneousPayment(preimage) => Some(preimage), + }; + channel_manager.claim_funds(payment_preimage.unwrap()); + }, + Event::PaymentClaimed { payment_hash, purpose, amount_msat, .. } => { + println!( + "\nEVENT: claimed payment from payment hash {} of {} millisatoshis", + payment_hash, amount_msat, ); - } else { - print!( - "\nEVENT: Failed fetch invoice for payment ID {}: {:?}", - payment_id, - if let Some(r) = reason { r } else { PaymentFailureReason::RetriesExhausted } + print!("> "); + std::io::stdout().flush().unwrap(); + let (payment_preimage, payment_secret) = match purpose { + PaymentPurpose::Bolt11InvoicePayment { + payment_preimage, payment_secret, .. + } => (payment_preimage, Some(payment_secret)), + PaymentPurpose::Bolt12OfferPayment { payment_preimage, payment_secret, .. } => { + (payment_preimage, Some(payment_secret)) + }, + PaymentPurpose::Bolt12RefundPayment { + payment_preimage, payment_secret, .. + } => (payment_preimage, Some(payment_secret)), + PaymentPurpose::SpontaneousPayment(preimage) => (Some(preimage), None), + }; + let write_future = { + let mut inbound = inbound_payments.lock().unwrap(); + match inbound.payments.entry(payment_hash) { + Entry::Occupied(mut e) => { + let payment = e.get_mut(); + payment.status = HTLCStatus::Succeeded; + payment.preimage = payment_preimage; + payment.secret = payment_secret; + }, + Entry::Vacant(e) => { + e.insert(PaymentInfo { + preimage: payment_preimage, + secret: payment_secret, + status: HTLCStatus::Succeeded, + amt_msat: MillisatAmount(Some(amount_msat)), + }); + }, + } + fs_store.write("", "", INBOUND_PAYMENTS_FNAME, inbound.encode()) + }; + write_future.await.unwrap(); + }, + Event::PaymentSent { + payment_preimage, payment_hash, fee_paid_msat, payment_id, .. + } => { + let write_future = { + let mut outbound = outbound_payments.lock().unwrap(); + for (id, payment) in outbound.payments.iter_mut() { + if *id == payment_id.unwrap() { + payment.preimage = Some(payment_preimage); + payment.status = HTLCStatus::Succeeded; + println!( + "\nEVENT: successfully sent payment of {} millisatoshis{} from \ + payment hash {} with preimage {}", + payment.amt_msat, + if let Some(fee) = fee_paid_msat { + format!(" (fee {} msat)", fee) + } else { + "".to_string() + }, + payment_hash, + payment_preimage + ); + print!("> "); + std::io::stdout().flush().unwrap(); + } + } + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound.encode()) + }; + write_future.await.unwrap(); + }, + Event::OpenChannelRequest { + ref temporary_channel_id, ref counterparty_node_id, .. + } => { + let mut random_bytes = [0u8; 16]; + random_bytes.copy_from_slice(&keys_manager.get_secure_random_bytes()[..16]); + let user_channel_id = u128::from_be_bytes(random_bytes); + let res = channel_manager.accept_inbound_channel( + temporary_channel_id, + counterparty_node_id, + user_channel_id, + None, ); - } - print!("> "); - std::io::stdout().flush().unwrap(); - let mut outbound = outbound_payments.lock().unwrap(); - if outbound.payments.contains_key(&payment_id) { - let payment = outbound.payments.get_mut(&payment_id).unwrap(); - payment.status = HTLCStatus::Failed; - } - fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); - }, - Event::InvoiceReceived { .. } => { - // We don't use the manual invoice payment logic, so this event should never be seen. - }, - Event::PaymentForwarded { - prev_channel_id, - next_channel_id, - total_fee_earned_msat, - claim_from_onchain_tx, - outbound_amount_forwarded_msat, - .. - } => { - let read_only_network_graph = network_graph.read_only(); - let nodes = read_only_network_graph.nodes(); - let channels = channel_manager.list_channels(); - - let node_str = |channel_id: &Option| match channel_id { - None => String::new(), - Some(channel_id) => match channels.iter().find(|c| c.channel_id == *channel_id) { + if let Err(e) = res { + print!( + "\nEVENT: Failed to accept inbound channel ({}) from {}: {:?}", + temporary_channel_id, + hex_utils::hex_str(&counterparty_node_id.serialize()), + e, + ); + } else { + print!( + "\nEVENT: Accepted inbound channel ({}) from {}", + temporary_channel_id, + hex_utils::hex_str(&counterparty_node_id.serialize()), + ); + } + print!("> "); + std::io::stdout().flush().unwrap(); + }, + Event::PaymentPathSuccessful { .. } => {}, + Event::PaymentPathFailed { .. } => {}, + Event::ProbeSuccessful { .. } => {}, + Event::ProbeFailed { .. } => {}, + Event::PaymentFailed { payment_hash, reason, payment_id, .. } => { + if let Some(hash) = payment_hash { + print!( + "\nEVENT: Failed to send payment to payment ID {}, payment hash {}: {:?}", + payment_id, + hash, + if let Some(r) = reason { r } else { PaymentFailureReason::RetriesExhausted } + ); + } else { + print!( + "\nEVENT: Failed fetch invoice for payment ID {}: {:?}", + payment_id, + if let Some(r) = reason { r } else { PaymentFailureReason::RetriesExhausted } + ); + } + print!("> "); + std::io::stdout().flush().unwrap(); + + let write_future = { + let mut outbound = outbound_payments.lock().unwrap(); + if outbound.payments.contains_key(&payment_id) { + let payment = outbound.payments.get_mut(&payment_id).unwrap(); + payment.status = HTLCStatus::Failed; + } + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, outbound.encode()) + }; + write_future.await.unwrap(); + }, + Event::InvoiceReceived { .. } => { + // We don't use the manual invoice payment logic, so this event should never be seen. + }, + Event::PaymentForwarded { + prev_channel_id, + next_channel_id, + total_fee_earned_msat, + claim_from_onchain_tx, + outbound_amount_forwarded_msat, + .. + } => { + let read_only_network_graph = network_graph.read_only(); + let nodes = read_only_network_graph.nodes(); + let channels = channel_manager.list_channels(); + + let node_str = |channel_id: &Option| match channel_id { None => String::new(), - Some(channel) => { - match nodes.get(&NodeId::from_pubkey(&channel.counterparty.node_id)) { - None => "private node".to_string(), - Some(node) => match &node.announcement_info { - None => "unnamed node".to_string(), - Some(announcement) => { - format!("node {}", announcement.alias()) + Some(channel_id) => match channels.iter().find(|c| c.channel_id == *channel_id) { + None => String::new(), + Some(channel) => { + match nodes.get(&NodeId::from_pubkey(&channel.counterparty.node_id)) { + None => "private node".to_string(), + Some(node) => match &node.announcement_info { + None => "unnamed node".to_string(), + Some(announcement) => { + format!("node {}", announcement.alias()) + }, }, - }, - } + } + }, }, - }, - }; - let channel_str = |channel_id: &Option| { - channel_id - .map(|channel_id| format!(" with channel {}", channel_id)) - .unwrap_or_default() - }; - let from_prev_str = - format!(" from {}{}", node_str(&prev_channel_id), channel_str(&prev_channel_id)); - let to_next_str = - format!(" to {}{}", node_str(&next_channel_id), channel_str(&next_channel_id)); - - let from_onchain_str = if claim_from_onchain_tx { - "from onchain downstream claim" - } else { - "from HTLC fulfill message" - }; - let amt_args = if let Some(v) = outbound_amount_forwarded_msat { - format!("{}", v) - } else { - "?".to_string() - }; - if let Some(fee_earned) = total_fee_earned_msat { + }; + let channel_str = |channel_id: &Option| { + channel_id + .map(|channel_id| format!(" with channel {}", channel_id)) + .unwrap_or_default() + }; + let from_prev_str = + format!(" from {}{}", node_str(&prev_channel_id), channel_str(&prev_channel_id)); + let to_next_str = + format!(" to {}{}", node_str(&next_channel_id), channel_str(&next_channel_id)); + + let from_onchain_str = if claim_from_onchain_tx { + "from onchain downstream claim" + } else { + "from HTLC fulfill message" + }; + let amt_args = if let Some(v) = outbound_amount_forwarded_msat { + format!("{}", v) + } else { + "?".to_string() + }; + if let Some(fee_earned) = total_fee_earned_msat { + println!( + "\nEVENT: Forwarded payment for {} msat{}{}, earning {} msat {}", + amt_args, from_prev_str, to_next_str, fee_earned, from_onchain_str + ); + } else { + println!( + "\nEVENT: Forwarded payment for {} msat{}{}, claiming onchain {}", + amt_args, from_prev_str, to_next_str, from_onchain_str + ); + } + print!("> "); + std::io::stdout().flush().unwrap(); + }, + Event::HTLCHandlingFailed { .. } => {}, + Event::SpendableOutputs { outputs, channel_id } => { + output_sweeper.0.track_spendable_outputs(outputs, channel_id, false, None).await.unwrap(); + }, + Event::ChannelPending { channel_id, counterparty_node_id, .. } => { println!( - "\nEVENT: Forwarded payment for {} msat{}{}, earning {} msat {}", - amt_args, from_prev_str, to_next_str, fee_earned, from_onchain_str + "\nEVENT: Channel {} with peer {} is pending awaiting funding lock-in!", + channel_id, + hex_utils::hex_str(&counterparty_node_id.serialize()), ); - } else { + print!("> "); + std::io::stdout().flush().unwrap(); + }, + Event::ChannelReady { + ref channel_id, + ref counterparty_node_id, + .. + } => { println!( - "\nEVENT: Forwarded payment for {} msat{}{}, claiming onchain {}", - amt_args, from_prev_str, to_next_str, from_onchain_str + "\nEVENT: Channel {} with peer {} is ready to be used!", + channel_id, + hex_utils::hex_str(&counterparty_node_id.serialize()), ); - } - print!("> "); - std::io::stdout().flush().unwrap(); - }, - Event::HTLCHandlingFailed { .. } => {}, - Event::PendingHTLCsForwardable { time_forwardable } => { - let forwarding_channel_manager = channel_manager.clone(); - let min = time_forwardable.as_millis() as u64; - tokio::spawn(async move { - let millis_to_sleep = thread_rng().gen_range(min, min * 5) as u64; - tokio::time::sleep(Duration::from_millis(millis_to_sleep)).await; - forwarding_channel_manager.process_pending_htlc_forwards(); - }); - }, - Event::SpendableOutputs { outputs, channel_id } => { - output_sweeper.0.track_spendable_outputs(outputs, channel_id, false, None).unwrap(); - }, - Event::ChannelPending { channel_id, counterparty_node_id, .. } => { - println!( - "\nEVENT: Channel {} with peer {} is pending awaiting funding lock-in!", - channel_id, - hex_utils::hex_str(&counterparty_node_id.serialize()), - ); - print!("> "); - std::io::stdout().flush().unwrap(); - }, - Event::ChannelReady { - ref channel_id, - user_channel_id: _, - ref counterparty_node_id, - channel_type: _, - } => { - println!( - "\nEVENT: Channel {} with peer {} is ready to be used!", - channel_id, - hex_utils::hex_str(&counterparty_node_id.serialize()), - ); - print!("> "); - std::io::stdout().flush().unwrap(); - }, - Event::ChannelClosed { channel_id, reason, counterparty_node_id, .. } => { - println!( - "\nEVENT: Channel {} with counterparty {} closed due to: {:?}", - channel_id, - counterparty_node_id.map(|id| format!("{}", id)).unwrap_or("".to_owned()), - reason - ); - print!("> "); - std::io::stdout().flush().unwrap(); - }, - Event::DiscardFunding { .. } => { - // A "real" node should probably "lock" the UTXOs spent in funding transactions until - // the funding transaction either confirms, or this event is generated. - }, - Event::HTLCIntercepted { .. } => {}, - Event::OnionMessageIntercepted { .. } => { - // We don't use the onion message interception feature, so this event should never be - // seen. - }, - Event::OnionMessagePeerConnected { .. } => { - // We don't use the onion message interception feature, so we have no use for this - // event. - }, - Event::BumpTransaction(event) => bump_tx_event_handler.handle_event(&event), - Event::ConnectionNeeded { node_id, addresses } => { - tokio::spawn(async move { - for address in addresses { - if let Ok(sockaddrs) = address.to_socket_addrs() { - for addr in sockaddrs { - let pm = Arc::clone(&peer_manager); - if cli::connect_peer_if_necessary(node_id, addr, pm).await.is_ok() { - return; + print!("> "); + std::io::stdout().flush().unwrap(); + }, + Event::ChannelClosed { channel_id, reason, counterparty_node_id, .. } => { + println!( + "\nEVENT: Channel {} with counterparty {} closed due to: {:?}", + channel_id, + counterparty_node_id.map(|id| format!("{}", id)).unwrap_or("".to_owned()), + reason + ); + print!("> "); + std::io::stdout().flush().unwrap(); + }, + Event::DiscardFunding { .. } => { + // A "real" node should probably "lock" the UTXOs spent in funding transactions until + // the funding transaction either confirms, or this event is generated. + }, + Event::HTLCIntercepted { .. } => {}, + Event::OnionMessageIntercepted { .. } => { + // We don't use the onion message interception feature, so this event should never be + // seen. + }, + Event::OnionMessagePeerConnected { .. } => { + // We don't use the onion message interception feature, so we have no use for this + // event. + }, + Event::BumpTransaction(event) => bump_tx_event_handler.handle_event(&event).await, + Event::ConnectionNeeded { node_id, addresses } => { + tokio::spawn(async move { + for address in addresses { + if let Ok(sockaddrs) = address.to_socket_addrs() { + for addr in sockaddrs { + let pm = Arc::clone(&peer_manager); + if cli::connect_peer_if_necessary(node_id, addr, pm).await.is_ok() { + return; + } } } } - } - }); - }, + }); + }, + _ => {}, + } } } @@ -644,34 +658,37 @@ async fn start_ldk() { // Step 5: Initialize Persistence let fs_store = Arc::new(FilesystemStore::new(ldk_data_dir.clone().into())); - let persister = Arc::new(MonitorUpdatingPersister::new( + let persister = MonitorUpdatingPersisterAsync::new( Arc::clone(&fs_store), + TokioSpawner, Arc::clone(&logger), 1000, Arc::clone(&keys_manager), Arc::clone(&keys_manager), Arc::clone(&bitcoind_client), Arc::clone(&bitcoind_client), - )); + ); // Alternatively, you can use the `FilesystemStore` as a `Persist` directly, at the cost of // larger `ChannelMonitor` update writes (but no deletion or cleanup): //let persister = Arc::clone(&fs_store); - // Step 6: Initialize the ChainMonitor - let chain_monitor: Arc = Arc::new(chainmonitor::ChainMonitor::new( + // Step 6: Read ChannelMonitor state from disk + let mut channelmonitors = persister.read_all_channel_monitors_with_updates().await.unwrap(); + // If you are using the `FilesystemStore` as a `Persist` directly, use + // `lightning::util::persist::read_channel_monitors` like this: + //read_channel_monitors(Arc::clone(&persister), Arc::clone(&keys_manager), Arc::clone(&keys_manager)).unwrap(); + + // Step 7: Initialize the ChainMonitor + let chain_monitor: Arc = Arc::new(chainmonitor::ChainMonitor::new_async_beta( None, Arc::clone(&broadcaster), Arc::clone(&logger), Arc::clone(&fee_estimator), - Arc::clone(&persister), + persister, + Arc::clone(&keys_manager), + keys_manager.get_peer_storage_key(), )); - // Step 7: Read ChannelMonitor state from disk - let mut channelmonitors = persister.read_all_channel_monitors_with_updates().unwrap(); - // If you are using the `FilesystemStore` as a `Persist` directly, use - // `lightning::util::persist::read_channel_monitors` like this: - //read_channel_monitors(Arc::clone(&persister), Arc::clone(&keys_manager), Arc::clone(&keys_manager)).unwrap(); - // Step 8: Poll for the best chain tip, which may be used by the channel manager & spv client let polled_chain_tip = init::validate_best_block_header(bitcoind_client.as_ref()) .await @@ -759,7 +776,7 @@ async fn start_ldk() { OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE, OUTPUT_SWEEPER_PERSISTENCE_KEY, - ) { + ).await { Err(e) if e.kind() == io::ErrorKind::NotFound => { let sweeper = OutputSweeper::new( channel_manager.current_best_block(), @@ -800,11 +817,11 @@ async fn start_ldk() { ]; for (blockhash, channel_monitor) in channelmonitors.drain(..) { - let outpoint = channel_monitor.get_funding_txo().0; + let funding_txo = channel_monitor.get_funding_txo(); chain_listener_channel_monitors.push(( blockhash, (channel_monitor, broadcaster.clone(), fee_estimator.clone(), logger.clone()), - outpoint, + funding_txo, )); } @@ -828,11 +845,12 @@ async fn start_ldk() { }; // Step 14: Give ChannelMonitors to ChainMonitor - for item in chain_listener_channel_monitors.drain(..) { - let channel_monitor = item.1 .0; - let funding_outpoint = item.2; + for (_, (channel_monitor, _, _, _), _) in chain_listener_channel_monitors { + let channel_id = channel_monitor.channel_id(); + // Note that this may not return `Completed` for ChannelMonitors which were last written by + // a version of LDK prior to 0.1. assert_eq!( - chain_monitor.watch_channel(funding_outpoint, channel_monitor), + chain_monitor.load_existing_monitor(channel_id, channel_monitor), Ok(ChannelMonitorUpdateStatus::Completed) ); } @@ -867,10 +885,11 @@ async fn start_ldk() { let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); rand::thread_rng().fill_bytes(&mut ephemeral_bytes); let lightning_msg_handler = MessageHandler { - chan_handler: channel_manager.clone(), - route_handler: gossip_sync.clone(), - onion_message_handler: onion_messenger.clone(), + chan_handler: Arc::clone(&channel_manager), + route_handler: Arc::clone(&gossip_sync), + onion_message_handler: Arc::clone(&onion_messenger), custom_message_handler: IgnoringMessageHandler {}, + send_only_message_handler: Arc::clone(&chain_monitor), }; let peer_manager: Arc = Arc::new(PeerManager::new( lightning_msg_handler, @@ -962,7 +981,8 @@ async fn start_ldk() { } } fs_store - .write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.lock().unwrap().encode()) + .write("", "", OUTBOUND_PAYMENTS_FNAME, outbound_payments.lock().unwrap().encode()) + .await .unwrap(); // Step 20: Handle LDK Events @@ -1007,21 +1027,20 @@ async fn start_ldk() { } }; - // Step 21: Persist ChannelManager and NetworkGraph - let persister = Arc::new(FilesystemStore::new(ldk_data_dir.clone().into())); - - // Step 22: Background Processing + // Step 21: Background Processing let (bp_exit, bp_exit_check) = tokio::sync::watch::channel(()); let mut background_processor = tokio::spawn(process_events_async( - Arc::clone(&persister), + Arc::clone(&fs_store), event_handler, - chain_monitor.clone(), - channel_manager.clone(), + Arc::clone(&chain_monitor), + Arc::clone(&channel_manager), Some(onion_messenger), - GossipSync::p2p(gossip_sync.clone()), - peer_manager.clone(), - logger.clone(), - Some(scorer.clone()), + GossipSync::p2p(Arc::clone(&gossip_sync)), + Arc::clone(&peer_manager), + NO_LIQUIDITY_MANAGER, + Some(Arc::clone(&output_sweeper)), + Arc::clone(&logger), + Some(Arc::clone(&scorer)), move |t| { let mut bp_exit_fut_check = bp_exit_check.clone(); Box::pin(async move { @@ -1038,37 +1057,46 @@ async fn start_ldk() { // Regularly reconnect to channel peers. let connect_cm = Arc::clone(&channel_manager); let connect_pm = Arc::clone(&peer_manager); - let peer_data_path = format!("{}/channel_peer_data", ldk_data_dir); let stop_connect = Arc::clone(&stop_listen_connect); + let graph_connect = Arc::clone(&network_graph); tokio::spawn(async move { let mut interval = tokio::time::interval(Duration::from_secs(1)); interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); loop { interval.tick().await; - match disk::read_channel_peer_data(Path::new(&peer_data_path)) { - Ok(info) => { - for node_id in connect_cm - .list_channels() - .iter() - .map(|chan| chan.counterparty.node_id) - .filter(|id| connect_pm.peer_by_node_id(id).is_none()) - { - if stop_connect.load(Ordering::Acquire) { - return; - } - for (pubkey, peer_addr) in info.iter() { - if *pubkey == node_id { - let _ = cli::do_connect_peer( - *pubkey, - peer_addr.clone(), - Arc::clone(&connect_pm), - ) - .await; + for node_id in connect_cm + .list_channels() + .iter() + .map(|chan| chan.counterparty.node_id) + .filter(|id| connect_pm.peer_by_node_id(id).is_none()) + { + if stop_connect.load(Ordering::Acquire) { + return; + } + let id = NodeId::from_pubkey(&node_id); + let addrs = if let Some(node) = graph_connect.read_only().node(&id) { + if let Some(ann) = &node.announcement_info { + ann.addresses().iter().filter_map(|addr| { + match addr { + lightning::ln::msgs::SocketAddress::OnionV2(_) => None, + lightning::ln::msgs::SocketAddress::OnionV3 { .. } => None, + _ => Some(addr.clone()), } - } + }).collect::>() + } else { + Vec::new() } - }, - Err(e) => println!("ERROR: errored reading channel peer info from disk: {:?}", e), + } else { + Vec::new() + }; + for addr in addrs { + let sockaddrs = addr.to_socket_addrs(); + if sockaddrs.is_err() { continue; } + for sockaddr in sockaddrs.unwrap() { + let _ = + cli::do_connect_peer(node_id, sockaddr, Arc::clone(&connect_pm)).await; + } + } } } }); @@ -1102,16 +1130,16 @@ async fn start_ldk() { ldk_data_dir.clone(), Arc::clone(&keys_manager), Arc::clone(&logger), - Arc::clone(&persister), + Arc::clone(&fs_store), Arc::clone(&output_sweeper), )); // Start the CLI. let cli_channel_manager = Arc::clone(&channel_manager); let cli_chain_monitor = Arc::clone(&chain_monitor); - let cli_persister = Arc::clone(&persister); + let cli_fs_store = Arc::clone(&fs_store); let cli_peer_manager = Arc::clone(&peer_manager); - let cli_poll = tokio::task::spawn_blocking(move || { + let cli_poll = tokio::task::spawn( cli::poll_for_user_input( cli_peer_manager, cli_channel_manager, @@ -1120,10 +1148,9 @@ async fn start_ldk() { network_graph, inbound_payments, outbound_payments, - ldk_data_dir, - cli_persister, + cli_fs_store, ) - }); + ); // Exit if either CLI polling exits or the background processor exits (which shouldn't happen // unless we fail to write to the filesystem). @@ -1141,13 +1168,14 @@ async fn start_ldk() { peer_manager.disconnect_all_peers(); if let Err(e) = bg_res { - let persist_res = persister + let persist_res = fs_store .write( persist::CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE, persist::CHANNEL_MANAGER_PERSISTENCE_SECONDARY_NAMESPACE, persist::CHANNEL_MANAGER_PERSISTENCE_KEY, - &channel_manager.encode(), + channel_manager.encode(), ) + .await .unwrap(); use lightning::util::logger::Logger; lightning::log_error!( diff --git a/src/sweep.rs b/src/sweep.rs index 7ab3b824..4dd21ee4 100644 --- a/src/sweep.rs +++ b/src/sweep.rs @@ -62,7 +62,8 @@ pub(crate) async fn migrate_deprecated_spendable_outputs( if !outputs.is_empty() { let key = hex_utils::hex_str(&keys_manager.get_secure_random_bytes()); persister - .write("spendable_outputs", "", &key, &WithoutLength(&outputs).encode()) + .write("spendable_outputs", "", &key, WithoutLength(&outputs).encode()) + .await .unwrap(); fs::remove_dir_all(&processing_spendables_dir).unwrap(); } @@ -90,7 +91,7 @@ pub(crate) async fn migrate_deprecated_spendable_outputs( } let spend_delay = Some(best_block.height + 2); - sweeper.track_spendable_outputs(outputs.clone(), None, false, spend_delay).unwrap(); + sweeper.track_spendable_outputs(outputs.clone(), None, false, spend_delay).await.unwrap(); fs::remove_dir_all(&spendables_dir).unwrap(); fs::remove_dir_all(&pending_spendables_dir).unwrap();