diff --git a/Cargo.lock b/Cargo.lock index 141df76c..4054813f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -91,15 +91,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" [[package]] name = "async-stream" @@ -120,18 +120,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -317,15 +317,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" @@ -372,12 +372,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -387,16 +384,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -407,9 +404,9 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "clap" -version = "4.4.18" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -417,9 +414,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -429,21 +426,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -513,9 +510,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -551,9 +548,9 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "equivalent" @@ -713,7 +710,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -765,9 +762,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" dependencies = [ "bytes", "fnv", @@ -775,7 +772,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.2", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -800,11 +797,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -835,9 +838,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -958,9 +961,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -992,9 +995,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1133,12 +1136,6 @@ dependencies = [ "lightning 0.0.120", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -1187,9 +1184,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "serde", ] @@ -1202,9 +1199,9 @@ checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" [[package]] name = "log4rs" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd" +checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6" dependencies = [ "anyhow", "arc-swap", @@ -1215,7 +1212,9 @@ dependencies = [ "libc", "log", "log-mdc", + "once_cell", "parking_lot", + "rand 0.8.5", "serde", "serde-value", "serde_json", @@ -1277,9 +1276,9 @@ dependencies = [ [[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 0.11.0+wasi-snapshot-preview1", @@ -1418,27 +1417,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.2", + "indexmap 2.2.5", ] [[package]] name = "pin-project" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -1455,9 +1454,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "ppv-lite86" @@ -1502,14 +1501,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1541,7 +1540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools 0.11.0", "log", "multimap", @@ -1551,7 +1550,7 @@ dependencies = [ "prost 0.12.3", "prost-types", "regex", - "syn 2.0.48", + "syn 2.0.53", "tempfile", "which", ] @@ -1579,7 +1578,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -1690,9 +1689,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1707,16 +1706,17 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin", "untrusted", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1733,11 +1733,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1783,9 +1783,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "scopeguard" @@ -1845,9 +1845,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -1864,20 +1864,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] name = "serde_json" -version = "1.0.113" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1886,14 +1886,15 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.26" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.2.5", + "itoa", "ryu", "serde", - "yaml-rust", + "unsafe-libyaml", ] [[package]] @@ -1913,12 +1914,12 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1929,9 +1930,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "syn" @@ -1946,9 +1947,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -1974,9 +1975,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -1992,22 +1993,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -2066,7 +2067,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -2081,9 +2082,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2185,7 +2186,7 @@ dependencies = [ "proc-macro2", "prost-build", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -2240,7 +2241,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", ] [[package]] @@ -2304,6 +2305,12 @@ dependencies = [ "destructure_traitobject", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -2345,9 +2352,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2355,24 +2362,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2380,22 +2387,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "webpki-roots" @@ -2443,7 +2450,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -2461,7 +2468,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -2481,17 +2488,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -2502,9 +2509,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -2514,9 +2521,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -2526,9 +2533,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -2538,9 +2545,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -2550,9 +2557,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -2562,9 +2569,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -2574,9 +2581,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "xattr" @@ -2589,15 +2596,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "zip" version = "0.5.13" diff --git a/config_spec.toml b/config_spec.toml index e1fa6304..4e84d5f4 100644 --- a/config_spec.toml +++ b/config_spec.toml @@ -12,16 +12,22 @@ doc = "LND GRPC address, kindly note that the address must start with https:// i name = "cert" type = "std::path::PathBuf" optional = false -doc = "The path to LND tls certificate file. Note: the abosolute tls certificate file path is required here." +doc = "The path to LND tls certificate file. Note: the absolute tls certificate file path is required here." [[param]] name = "macaroon" type = "std::path::PathBuf" optional = false -doc = "The path to LND macaroon file. Note: the abosolute macaroon file path is required here." +doc = "The path to LND macaroon file. Note: the absolute macaroon file path is required here." [[param]] name = "log_dir" type = "String" doc = "The path to the lndk log file" + +[[param]] +name = "auto_connect" +type = "bool" +default = "false" +doc = "When starting up lndk, auto connects to some random nodes that support onion messaging to help forward onion messages." diff --git a/src/lib.rs b/src/lib.rs index 80e2c3e9..fb0ee07f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use crate::lnd::{ features_support_onion_messages, get_lnd_client, string_to_network, LndCfg, LndNodeSigner, }; use crate::lndk_offers::{OfferError, PayInvoiceParams}; -use crate::onion_messenger::MessengerUtilities; +use crate::onion_messenger::{connect_to_onion_peers, MessengerUtilities}; use bitcoin::network::constants::Network; use bitcoin::secp256k1::{Error as Secp256k1Error, PublicKey, Secp256k1}; use home::home_dir; @@ -41,9 +41,13 @@ use triggered::{Listener, Trigger}; static INIT: Once = Once::new(); +/// The number of peers we'll target to connect to in auto connect mode. +const NUM_PEER_TARGET: u8 = 3; + pub struct Cfg { pub lnd: LndCfg, pub log_dir: Option, + pub auto_connect: bool, pub signals: LifecycleSignals, } @@ -153,6 +157,17 @@ impl LndkOnionMessenger { peer_support.insert(pubkey, onion_support); } + // If the auto connect option is turned on and we aren't connected to the targeted number of peers + // that support onion messaging, we'll automatically connect to some. + if args.auto_connect && peer_support.len() < NUM_PEER_TARGET.into() { + let peer_num = NUM_PEER_TARGET - u8::try_from(peer_support.len()).unwrap(); + connect_to_onion_peers(client.clone(), peer_num, peer_support.clone(), pubkey) + .await + .map_err(|e| { + error!("Could not connect to peers: {e}."); + })?; + } + // Create an onion messenger that depends on LND's signer client and consume related events. let mut node_client = client.signer().clone(); let node_signer = LndNodeSigner::new(pubkey, &mut node_client); diff --git a/src/lnd.rs b/src/lnd.rs index 98b07fcc..bb4d4507 100644 --- a/src/lnd.rs +++ b/src/lnd.rs @@ -17,12 +17,14 @@ use std::collections::HashMap; use std::error::Error; use std::fmt; use std::path::PathBuf; -use tonic_lnd::lnrpc::{HtlcAttempt, LightningNode, ListPeersResponse, QueryRoutesResponse, Route}; +use tonic_lnd::lnrpc::{ + ChannelGraph, HtlcAttempt, LightningNode, ListPeersResponse, QueryRoutesResponse, Route, +}; use tonic_lnd::signrpc::KeyLocator; use tonic_lnd::tonic::Status; use tonic_lnd::{Client, ConnectError}; -const ONION_MESSAGES_REQUIRED: u32 = 38; +pub(crate) const ONION_MESSAGES_REQUIRED: u32 = 38; pub(crate) const ONION_MESSAGES_OPTIONAL: u32 = 39; /// get_lnd_client connects to LND's grpc api using the config provided, blocking until a connection is established. @@ -204,12 +206,14 @@ pub trait MessageSigner { ) -> Result>; } -/// PeerConnector provides a layer of abstraction over the LND API for connecting to a peer. +/// PeerConnector provides a layer of abstraction over the LND API for browsing the network graph or connecting to +/// a peer. #[async_trait] pub trait PeerConnector { async fn list_peers(&mut self) -> Result; async fn connect_peer(&mut self, node_id: String, addr: String) -> Result<(), Status>; async fn get_node_info(&mut self, pub_key: String) -> Result, Status>; + async fn describe_graph(&mut self) -> Result; } /// InvoicePayer provides a layer of abstraction over the LND API for paying for a BOLT 12 invoice. diff --git a/src/lndk_offers.rs b/src/lndk_offers.rs index 102ea1e3..571ed7b4 100644 --- a/src/lndk_offers.rs +++ b/src/lndk_offers.rs @@ -22,7 +22,7 @@ use std::str::FromStr; use tokio::sync::mpsc::Receiver; use tokio::task; use tonic_lnd::lnrpc::{ - GetInfoRequest, HtlcAttempt, LightningNode, ListPeersRequest, ListPeersResponse, + ChannelGraph, GetInfoRequest, HtlcAttempt, LightningNode, ListPeersRequest, ListPeersResponse, QueryRoutesResponse, Route, }; use tonic_lnd::routerrpc::TrackPaymentRequest; @@ -217,7 +217,7 @@ impl OfferHandler { /// create_reply_path creates a blinded path to provide to the offer maker when requesting an /// invoice so they know where to send the invoice back to. We try to find a peer that we're /// connected to with onion messaging support that we can use to form a blinded path, - /// otherwise we creae a blinded path directly to ourselves. + /// otherwise we create a blinded path directly to ourselves. pub async fn create_reply_path( &self, mut connector: impl PeerConnector + std::marker::Send + 'static, @@ -438,6 +438,17 @@ impl PeerConnector for Client { .await .map(|resp| resp.into_inner().node) } + + async fn describe_graph(&mut self) -> Result { + let req = tonic_lnd::lnrpc::ChannelGraphRequest { + include_unannounced: false, + }; + + self.lightning() + .describe_graph(req) + .await + .map(|resp| resp.into_inner()) + } } #[async_trait] @@ -664,6 +675,7 @@ mod tests { async fn list_peers(&mut self) -> Result; async fn get_node_info(&mut self, pub_key: String) -> Result, Status>; async fn connect_peer(&mut self, node_id: String, addr: String) -> Result<(), Status>; + async fn describe_graph(&mut self) -> Result; } } diff --git a/src/main.rs b/src/main.rs index a98fb46e..6b54b600 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ async fn main() -> Result<(), ()> { let args = Cfg { lnd: lnd_args, log_dir: config.log_dir, + auto_connect: config.auto_connect, signals, }; diff --git a/src/onion_messenger.rs b/src/onion_messenger.rs index d36607c0..0a99a275 100644 --- a/src/onion_messenger.rs +++ b/src/onion_messenger.rs @@ -1,5 +1,8 @@ use crate::clock::TokioClock; -use crate::lnd::{features_support_onion_messages, ONION_MESSAGES_OPTIONAL}; +use crate::lnd::{ + features_support_onion_messages, PeerConnector, ONION_MESSAGES_OPTIONAL, + ONION_MESSAGES_REQUIRED, +}; use crate::rate_limit::{RateLimiter, TokenLimiter}; use crate::{LifecycleSignals, LndkOnionMessenger}; use async_trait::async_trait; @@ -31,7 +34,7 @@ use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::{select, time, time::Duration, time::Interval}; use tonic_lnd::{ lnrpc::peer_event::EventType::PeerOffline, lnrpc::peer_event::EventType::PeerOnline, - lnrpc::CustomMessage, lnrpc::PeerEvent, lnrpc::SendCustomMessageRequest, + lnrpc::ChannelGraph, lnrpc::CustomMessage, lnrpc::PeerEvent, lnrpc::SendCustomMessageRequest, lnrpc::SendCustomMessageResponse, tonic::Status, LightningClient, }; use triggered::Listener; @@ -299,6 +302,65 @@ async fn lookup_onion_support(pubkey: &PublicKey, client: &mut tonic_lnd::Lightn } } +/// connect_to_onion_peers picks a few random nodes from the network graph that support onion messenging, then +/// connects to them. +pub(crate) async fn connect_to_onion_peers( + mut connector: impl PeerConnector + std::marker::Send + 'static, + target_peers: u8, + current_peers: HashMap, + lnd_key: PublicKey, +) -> Result<(), Status> { + let graph = connector.describe_graph().await?; + + let onion_peers = get_onion_peers(graph, target_peers, current_peers, lnd_key).await; + //for i in 0..onion_peers.len() { + for peer in onion_peers.iter() { + connector + .connect_peer(peer.0.clone(), peer.1.clone()) + .await? + } + + Ok(()) +} + +/// get_onion_peers picks a few onion-messenging-supporting nodes from the network graph. +async fn get_onion_peers( + graph: ChannelGraph, + target_peers: u8, + current_peers: HashMap, + lnd_key: PublicKey, +) -> Vec<(String, String)> { + let mut onion_peers = Vec::new(); + let mut num = 0; + for node in graph.nodes.iter() { + if node.features.contains_key(&ONION_MESSAGES_REQUIRED) + || node.features.contains_key(&ONION_MESSAGES_OPTIONAL) + { + // We don't want to connect to ourself. + if node.pub_key == lnd_key.to_string() { + continue; + } + + if current_peers + .get(&PublicKey::from_str(&node.pub_key).unwrap()) + .is_some() + { + continue; + } + + if !node.addresses.is_empty() { + onion_peers.push((node.pub_key.clone(), node.addresses[0].addr.clone())); + num += 1; + } + if num >= target_peers { + break; + } + } + } + + onion_peers +} + #[derive(Debug)] /// ProducerError represents the exit of a producing loop. enum ProducerError { @@ -589,14 +651,14 @@ async fn consume_messenger_events( .map_err(|_| ConsumerError::OnionMessengerFailure)?; // In addition to keeping the onion messenger up to date with the latest peers, we need to keep our - // local version up to date so we send outgoing OMs all of our peers. + // local version up to date so we send outgoing onion messages to all of our peers. rate_limiter.peer_connected(pubkey); } MessengerEvents::PeerDisconnected(pubkey) => { onion_messenger.peer_disconnected(&pubkey); // In addition to keeping the onion messenger up to date with the latest peers, we need to keep our - // local version up to date so we send outgoing OMs to our correct peers. + // local version up to date so we send outgoing onion messages to our correct peers. rate_limiter.peer_disconnected(pubkey); } MessengerEvents::IncomingMessage(pubkey, onion_message) => { @@ -650,7 +712,7 @@ impl SendCustomMessage for CustomMessenger { } } -/// produce_outgoing_message_events is produce for producing outgoing message events at a regular interval. +/// produce_outgoing_message_events produces outgoing message events at a regular interval. /// /// Note that this function *must* send an exit error to the Sender provided on all exit-cases, so that upstream /// consumers know to exit as well. Failures related to sending events are an exception, as failure to send indicates @@ -728,6 +790,7 @@ mod tests { use mockall::mock; use std::io::Cursor; use tokio::sync::mpsc::channel; + use tonic_lnd::lnrpc::{Feature, LightningNode, NodeAddress}; /// Produces an OnionMessage that can be used for tests. We need to manually write individual bytes because onion /// messages in LDK can only be created using read/write impls that deal with raw bytes (since some other fields @@ -1129,4 +1192,70 @@ mod tests { .await .is_ok()); } + + #[tokio::test] + async fn test_get_onion_peers() { + let feature_value = Feature { + ..Default::default() + }; + let mut features_optional = HashMap::new(); + features_optional.insert(ONION_MESSAGES_OPTIONAL, feature_value.clone()); + let mut features_required = HashMap::new(); + features_required.insert(ONION_MESSAGES_REQUIRED, feature_value); + + let address = NodeAddress { + network: String::from("tcp"), + addr: String::from("http://127.0.0.1:9735"), + }; + let mut addresses = Vec::new(); + addresses.push(address); + + let mut nodes = Vec::new(); + let node1 = LightningNode { + features: features_optional, + addresses: addresses.clone(), + pub_key: pubkey(2).to_string(), + ..Default::default() + }; + let node2 = LightningNode { + features: features_required, + addresses: addresses.clone(), + pub_key: pubkey(3).to_string(), + ..Default::default() + }; + let node3 = LightningNode { + features: HashMap::new(), + addresses: addresses, + ..Default::default() + }; + nodes.push(node1); + nodes.push(node2.clone()); + nodes.push(node3); + + let graph = ChannelGraph { + nodes: nodes.clone(), + ..Default::default() + }; + + let current_peers = HashMap::new(); + let pk_1 = pubkey(1); + + // Make sure get_onion_peers correctly only identifies the two nodes that advertise onion messaging support. + let onion_peers = get_onion_peers(graph, 3, current_peers.clone(), pk_1.clone()).await; + assert!(onion_peers.len() == 2); + + // Now let's add a couple more onion-message-supporting nodes to our graph. If there's four such nodes + // in the graph, make sure get_onion_peers only grabs three of them (since that's how many we request + // by default). + nodes.push(node2.clone()); + nodes.push(node2); + + let graph = ChannelGraph { + nodes: nodes, + ..Default::default() + }; + + let onion_peers = get_onion_peers(graph, 3, current_peers, pk_1).await; + assert!(onion_peers.len() == 3); + } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9b370d73..3181d959 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -7,6 +7,7 @@ use bitcoind::{get_available_port, BitcoinD, Conf, ConnectParams}; use chrono::Utc; use ldk_sample::config::LdkUserInfo; use ldk_sample::node_api::Node as LdkNode; +use ldk_sample::start_ldk; use lightning::util::logger::Level; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::path::PathBuf; @@ -67,8 +68,8 @@ pub async fn setup_test_infrastructure( node_num: 2, }; - let ldk1 = ldk_sample::start_ldk(ldk1_config, test_name).await; - let ldk2 = ldk_sample::start_ldk(ldk2_config, test_name).await; + let ldk1 = start_ldk(ldk1_config, test_name).await; + let ldk2 = start_ldk(ldk2_config, test_name).await; (bitcoind, lnd, ldk1, ldk2, lndk_test_dir) } @@ -360,6 +361,28 @@ impl LndNode { resp } + pub async fn list_peers(&mut self) -> tonic_lnd::lnrpc::ListPeersResponse { + let list_req = tonic_lnd::lnrpc::ListPeersRequest { + ..Default::default() + }; + + let resp = if let Some(client) = self.client.clone() { + let make_request = || async { + client + .clone() + .lightning() + .list_peers(list_req.clone()) + .await + }; + let resp = test_utils::retry_async(make_request, String::from("list_peers")); + resp.await.unwrap() + } else { + panic!("No client") + }; + + resp + } + // wait_for_chain_sync waits until we're synced to chain according to the get_info response. // We'll timeout if it takes too long. pub async fn wait_for_chain_sync(&mut self) { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index a9a921ca..4159d4f4 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -5,13 +5,13 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1}; use bitcoin::Network; use bitcoincore_rpc::bitcoin::Network as RpcNetwork; use bitcoincore_rpc::RpcApi; -use chrono::Utc; use ldk_sample::node_api::Node as LdkNode; use lightning::blinded_path::BlindedPath; use lightning::offers::offer::Quantity; use lightning::onion_message::messenger::Destination; +use lndk::lnd::LndCfg; use lndk::onion_messenger::MessengerUtilities; -use lndk::{LifecycleSignals, PayOfferParams}; +use lndk::{LifecycleSignals, LndkOnionMessenger, PayOfferParams}; use std::net::SocketAddr; use std::path::PathBuf; use std::str::FromStr; @@ -21,6 +21,47 @@ use tokio::sync::mpsc; use tokio::sync::mpsc::{Receiver, Sender}; use tokio::time::{sleep, timeout, Duration}; +struct Lndk { + cfg: lndk::Cfg, + messenger: LndkOnionMessenger, + rx: Receiver, + shutdown: triggered::Trigger, +} + +async fn setup_lndk(lnd_cfg: LndCfg, auto_connect: bool, lndk_dir: PathBuf) -> Lndk { + let (shutdown, listener) = triggered::trigger(); + let (tx, rx): (Sender, Receiver) = mpsc::channel(1); + + let signals = LifecycleSignals { + shutdown: shutdown.clone(), + listener, + started: tx, + }; + + let cfg = lndk::Cfg { + lnd: lnd_cfg, + auto_connect: auto_connect, + log_dir: Some( + lndk_dir + .join(format!("lndk-logs.txt")) + .to_str() + .unwrap() + .to_string(), + ), + signals, + }; + + let handler = lndk::OfferHandler::new(); + let messenger = lndk::LndkOnionMessenger::new(handler); + + Lndk { + cfg, + messenger, + rx, + shutdown, + } +} + async fn wait_to_receive_onion_message( ldk1: LdkNode, ldk2: LdkNode, @@ -70,41 +111,19 @@ async fn test_lndk_forwards_onion_message() { // Now we'll spin up lndk. Even though ldk1 and ldk2 are not directly connected, we'll show that lndk // successfully helps lnd forward the onion message from ldk1 to ldk2. - let (shutdown, listener) = triggered::trigger(); - let lnd_cfg = lndk::lnd::LndCfg::new( + let lnd_cfg = LndCfg::new( lnd.address, PathBuf::from_str(&lnd.cert_path).unwrap(), PathBuf::from_str(&lnd.macaroon_path).unwrap(), ); - let now_timestamp = Utc::now(); - let timestamp = now_timestamp.format("%d-%m-%Y-%H%M"); - let (tx, _): (Sender, Receiver) = mpsc::channel(1); - let signals = LifecycleSignals { - shutdown: shutdown.clone(), - listener, - started: tx, - }; - let lndk_cfg = lndk::Cfg { - lnd: lnd_cfg, - log_dir: Some( - lndk_dir - .join(format!("lndk-logs-{test_name}-{timestamp}")) - .to_str() - .unwrap() - .to_string(), - ), - signals, - }; - - let handler = lndk::OfferHandler::new(); - let messenger = lndk::LndkOnionMessenger::new(handler); + let lndk = setup_lndk(lnd_cfg, false, lndk_dir).await; select! { - val = messenger.run(lndk_cfg) => { + val = lndk.messenger.run(lndk.cfg) => { panic!("lndk should not have completed first {:?}", val); }, // We wait for ldk2 to receive the onion message. (ldk1, ldk2) = wait_to_receive_onion_message(ldk1, ldk2, PublicKey::from_str(&lnd_info.identity_pubkey).unwrap()) => { - shutdown.trigger(); + lndk.shutdown.trigger(); ldk1.stop().await; ldk2.stop().await; } @@ -183,30 +202,11 @@ async fn test_lndk_send_invoice_request() { .expect("should create offer"); // Now we'll spin up lndk, which should forward the invoice request to ldk2. - let (shutdown, listener) = triggered::trigger(); - let lnd_cfg = lndk::lnd::LndCfg::new( + let lnd_cfg = LndCfg::new( lnd.address.clone(), PathBuf::from_str(&lnd.cert_path).unwrap(), PathBuf::from_str(&lnd.macaroon_path).unwrap(), ); - let (tx, rx): (Sender, Receiver) = mpsc::channel(1); - let signals = LifecycleSignals { - shutdown: shutdown.clone(), - listener, - started: tx, - }; - - let lndk_cfg = lndk::Cfg { - lnd: lnd_cfg.clone(), - log_dir: Some( - lndk_dir - .join(format!("lndk-logs.txt")) - .to_str() - .unwrap() - .to_string(), - ), - signals, - }; let mut client = lnd.client.clone().unwrap(); let blinded_path = offer.paths()[0].clone(); @@ -237,8 +237,7 @@ async fn test_lndk_send_invoice_request() { } // Make sure lndk successfully sends the invoice_request. - let handler = lndk::OfferHandler::new(); - let messenger = lndk::LndkOnionMessenger::new(handler); + let lndk = setup_lndk(lnd_cfg.clone(), false, lndk_dir.clone()).await; let pay_cfg = PayOfferParams { offer: offer.clone(), amount: Some(20_000), @@ -248,11 +247,11 @@ async fn test_lndk_send_invoice_request() { reply_path: Some(reply_path.clone()), }; select! { - val = messenger.run(lndk_cfg) => { + val = lndk.messenger.run(lndk.cfg) => { panic!("lndk should not have completed first {:?}", val); }, // We wait for ldk2 to receive the onion message. - res = messenger.offer_handler.send_invoice_request(pay_cfg.clone(), rx) => { + res = lndk.messenger.offer_handler.send_invoice_request(pay_cfg.clone(), lndk.rx) => { assert!(res.is_ok()); } } @@ -262,36 +261,15 @@ async fn test_lndk_send_invoice_request() { lnd.disconnect_peer(pubkey_2).await; lnd.wait_for_chain_sync().await; - let (shutdown, listener) = triggered::trigger(); - let (tx, rx): (Sender, Receiver) = mpsc::channel(1); - let signals = LifecycleSignals { - shutdown: shutdown.clone(), - listener, - started: tx, - }; - - let lndk_cfg = lndk::Cfg { - lnd: lnd_cfg, - log_dir: Some( - lndk_dir - .join(format!("lndk-logs.txt")) - .to_str() - .unwrap() - .to_string(), - ), - signals, - }; - - let handler = lndk::OfferHandler::new(); - let messenger = lndk::LndkOnionMessenger::new(handler); + let lndk = setup_lndk(lnd_cfg, false, lndk_dir).await; select! { - val = messenger.run(lndk_cfg) => { + val = lndk.messenger.run(lndk.cfg) => { panic!("lndk should not have completed first {:?}", val); }, // We wait for ldk2 to receive the onion message. - res = messenger.offer_handler.send_invoice_request(pay_cfg, rx) => { + res = lndk.messenger.offer_handler.send_invoice_request(pay_cfg, lndk.rx) => { assert!(res.is_ok()); - shutdown.trigger(); + lndk.shutdown.trigger(); ldk1.stop().await; ldk2.stop().await; } @@ -384,31 +362,12 @@ async fn test_lndk_pay_offer() { .await .expect("should create offer"); - let (shutdown, listener) = triggered::trigger(); - let lnd_cfg = lndk::lnd::LndCfg::new( + let lnd_cfg = LndCfg::new( lnd.address.clone(), PathBuf::from_str(&lnd.cert_path).unwrap(), PathBuf::from_str(&lnd.macaroon_path).unwrap(), ); - let (tx, rx): (Sender, Receiver) = mpsc::channel(1); - - let signals = LifecycleSignals { - shutdown: shutdown.clone(), - listener, - started: tx, - }; - - let lndk_cfg = lndk::Cfg { - lnd: lnd_cfg, - log_dir: Some( - lndk_dir - .join(format!("lndk-logs.txt")) - .to_str() - .unwrap() - .to_string(), - ), - signals, - }; + let lndk = setup_lndk(lnd_cfg, false, lndk_dir).await; let messenger_utils = MessengerUtilities::new(); let client = lnd.client.clone().unwrap(); @@ -417,9 +376,6 @@ async fn test_lndk_pay_offer() { let reply_path = BlindedPath::new_for_message(&[pubkey_2, lnd_pubkey], &messenger_utils, &secp_ctx).unwrap(); - // Make sure lndk successfully sends the invoice_request. - let handler = lndk::OfferHandler::new(); - let messenger = lndk::LndkOnionMessenger::new(handler); let pay_cfg = PayOfferParams { offer, amount: Some(20_000), @@ -429,13 +385,114 @@ async fn test_lndk_pay_offer() { reply_path: Some(reply_path), }; select! { - val = messenger.run(lndk_cfg) => { + val = lndk.messenger.run(lndk.cfg) => { panic!("lndk should not have completed first {:?}", val); }, // We wait for ldk2 to receive the onion message. - res = messenger.offer_handler.pay_offer(pay_cfg, rx) => { + res = lndk.messenger.offer_handler.pay_offer(pay_cfg, lndk.rx) => { assert!(res.is_ok()); - shutdown.trigger(); + lndk.shutdown.trigger(); + ldk1.stop().await; + ldk2.stop().await; + } + } +} + +#[tokio::test(flavor = "multi_thread")] +// Tests that the auto connect option appropriately auto-connects to peers advertising onion messaging +// support. +async fn test_auto_connect() { + let test_name = "auto_connect"; + let (bitcoind, mut lnd, ldk1, ldk2, lndk_dir) = + common::setup_test_infrastructure(test_name).await; + + // To test this feature, we'll connect lnd to ldk1. We'll connect ldk1 to ldk2 with a channel. + // lnd <--- peer connection ---> ldk1 <--- channels ---> ldk2 + // Lnd should then get a gossip message from ldk1 about its channel with ldk2 (we'll wait for gossip network sync) + let (pubkey, addr) = ldk1.get_node_info(); + let (pubkey_2, addr_2) = ldk2.get_node_info(); + + lnd.connect_to_peer(pubkey, addr).await; + ldk1.connect_to_peer(pubkey_2, addr_2).await.unwrap(); + + let ldk1_fund_addr = ldk1.bitcoind_client.get_new_address().await; + + // We need to convert funding addresses to the form that the bitcoincore_rpc library recognizes. + let ldk1_addr_string = ldk1_fund_addr.to_string(); + let ldk1_addr = bitcoind::bitcoincore_rpc::bitcoin::Address::from_str(&ldk1_addr_string) + .unwrap() + .require_network(RpcNetwork::Regtest) + .unwrap(); + + bitcoind + .node + .client + .generate_to_address(6, &ldk1_addr) + .unwrap(); + + lnd.wait_for_chain_sync().await; + + ldk1.open_channel(pubkey_2, addr_2, 200000, 0, true) + .await + .unwrap(); + + lnd.wait_for_graph_sync().await; + + bitcoind + .node + .client + .generate_to_address(10, &ldk1_addr) + .unwrap(); + + lnd.wait_for_chain_sync().await; + + let mut client = lnd.client.clone().unwrap(); + let mut stream = client + .lightning() + .subscribe_channel_graph(tonic_lnd::lnrpc::GraphTopologySubscription {}) + .await + .unwrap() + .into_inner(); + + // Wait for ldk2's graph update to come through, otherwise we won't be able to auto-connect to + // it by looking at lnd's network graph. + 'outer: while let Some(update) = stream.message().await.unwrap() { + for node in update.node_updates.iter() { + for node_addr in node.node_addresses.iter() { + if node_addr.addr == addr_2.to_string() { + break 'outer; + } + } + } + } + + let lnd_cfg = LndCfg::new( + lnd.address.clone(), + PathBuf::from_str(&lnd.cert_path).unwrap(), + PathBuf::from_str(&lnd.macaroon_path).unwrap(), + ); + + let mut lndk = setup_lndk(lnd_cfg, true, lndk_dir).await; + select! { + val = lndk.messenger.run(lndk.cfg) => { + panic!("lndk should not have completed first {:?}", val); + }, + // Wait for onion messenger to give us the signal that it started up. + _ = lndk.rx.recv() => { + // Now we can check that lndk successfully auto-connected to one more peer than before. + let resp = lnd.list_peers().await; + assert!(resp.peers.len() == 2); + + // Check that we're connected to the peer we expected. + let mut connected = false; + for peer in resp.peers.iter() { + if PublicKey::from_str(&peer.pub_key).unwrap() == pubkey_2 { + connected = true; + } + } + assert!(connected); + + lndk.shutdown.trigger(); ldk1.stop().await; ldk2.stop().await; }