1441: Dynamically choose monero daemon to connect to r=delta1 a=binarybaron

The GUI now does this with https://github.com/UnstoppableSwap/unstoppableswap-gui/pull/157. However, ideally, this should be handled by swap itself and not by a third party wrapper which is why this PR implements a similar behaviour for  swap. On startup we loop through list of public Monero daemons and choose one dynamically based on their response to the get_info RPC call.

Co-authored-by: binarybaron <86064887+binarybaron@users.noreply.github.com>
pull/1443/head
bors[bot] 8 months ago committed by GitHub
commit 7d6b1c2244
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

282
Cargo.lock generated

@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
@ -105,6 +120,16 @@ version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3"
[[package]]
name = "assert-json-diff"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "async-compression"
version = "0.3.15"
@ -114,7 +139,7 @@ dependencies = [
"bzip2",
"futures-core",
"memchr",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"tokio",
]
@ -139,7 +164,7 @@ dependencies = [
"futures-sink",
"futures-util",
"memchr",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
]
[[package]]
@ -186,11 +211,26 @@ dependencies = [
"futures-core",
"getrandom 0.2.6",
"instant",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"rand 0.8.3",
"tokio",
]
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if 1.0.0",
"libc",
"miniz_oxide 0.7.1",
"object",
"rustc-demangle",
]
[[package]]
name = "base32"
version = "0.4.0"
@ -359,6 +399,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "blake2"
version = "0.9.2"
@ -423,7 +469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "822462c1e7b17b31961798a6874b36daea6818e99e0cb7d3b7b0fa3c477751c3"
dependencies = [
"borsh-derive",
"hashbrown 0.11.2",
"hashbrown 0.12.3",
]
[[package]]
@ -616,7 +662,7 @@ checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term 0.11.0",
"atty",
"bitflags",
"bitflags 1.3.2",
"strsim 0.8.0",
"textwrap",
"unicode-width",
@ -629,6 +675,17 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "colored"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6"
dependencies = [
"is-terminal",
"lazy_static",
"windows-sys 0.48.0",
]
[[package]]
name = "comfy-table"
version = "6.1.4"
@ -804,7 +861,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"crossterm_winapi",
"libc",
"mio",
@ -1225,7 +1282,7 @@ dependencies = [
"crc32fast",
"libc",
"libz-sys",
"miniz_oxide",
"miniz_oxide 0.3.7",
]
[[package]]
@ -1384,7 +1441,7 @@ dependencies = [
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"pin-utils",
"slab",
]
@ -1459,13 +1516,19 @@ dependencies = [
"polyval",
]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "git2"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libc",
"libgit2-sys",
"log",
@ -1664,7 +1727,7 @@ dependencies = [
"httparse",
"httpdate",
"itoa 1.0.1",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"socket2 0.4.7",
"tokio",
"tower-service",
@ -1784,6 +1847,17 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135"
[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
dependencies = [
"hermit-abi 0.3.1",
"rustix 0.38.11",
"windows-sys 0.48.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -1871,9 +1945,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.141"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "libgit2-sys"
@ -2211,6 +2285,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
[[package]]
name = "linux-raw-sys"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "lock_api"
version = "0.4.6"
@ -2323,16 +2403,45 @@ dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.4"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.36.1",
"windows-sys 0.48.0",
]
[[package]]
name = "mockito"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09c762b6267c4593555bb38f1df19e9318985bc4de60b5e8462890856a9a5b4c"
dependencies = [
"assert-json-diff",
"colored",
"futures",
"hyper",
"lazy_static",
"log",
"rand 0.8.3",
"regex",
"serde_json",
"serde_urlencoded",
"similar",
"tokio",
]
[[package]]
@ -2593,6 +2702,15 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.13.0"
@ -2785,9 +2903,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
@ -2904,7 +3022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65"
dependencies = [
"bit-set",
"bitflags",
"bitflags 1.3.2",
"byteorder",
"lazy_static",
"num-traits",
@ -3159,7 +3277,7 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -3168,7 +3286,7 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -3183,9 +3301,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.5.5"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
dependencies = [
"aho-corasick",
"memchr",
@ -3204,9 +3322,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "rend"
@ -3239,7 +3357,7 @@ dependencies = [
"mime",
"once_cell",
"percent-encoding",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"rustls 0.21.1",
"rustls-pemfile",
"serde",
@ -3337,6 +3455,12 @@ dependencies = [
"rust_decimal",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hex"
version = "2.1.0"
@ -3364,11 +3488,24 @@ version = "0.37.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"linux-raw-sys 0.3.1",
"windows-sys 0.48.0",
]
[[package]]
name = "rustix"
version = "0.38.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
dependencies = [
"bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys 0.4.5",
"windows-sys 0.48.0",
]
@ -3556,7 +3693,7 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
@ -3814,6 +3951,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f0242b8e50dd9accdd56170e94ca1ebd223b098eb9c83539a6e367d0f36ae68"
[[package]]
name = "similar"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
[[package]]
name = "slab"
version = "0.4.2"
@ -3881,6 +4024,16 @@ dependencies = [
"winapi",
]
[[package]]
name = "socket2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "soketto"
version = "0.7.0"
@ -3950,7 +4103,7 @@ checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
dependencies = [
"ahash",
"atoi",
"bitflags",
"bitflags 1.3.2",
"byteorder",
"bytes",
"crc",
@ -4144,6 +4297,7 @@ dependencies = [
"hyper",
"itertools",
"libp2p",
"mockito",
"monero",
"monero-harness",
"monero-rpc",
@ -4233,7 +4387,7 @@ dependencies = [
"cfg-if 1.0.0",
"fastrand",
"redox_syscall 0.3.5",
"rustix",
"rustix 0.37.11",
"windows-sys 0.48.0",
]
@ -4381,33 +4535,32 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.19.2"
version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [
"backtrace",
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"once_cell",
"parking_lot 0.12.0",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"signal-hook-registry",
"socket2 0.4.7",
"socket2 0.5.3",
"tokio-macros",
"winapi",
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-macros"
version = "1.7.0"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.15",
]
[[package]]
@ -4461,7 +4614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce"
dependencies = [
"futures-core",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"tokio",
]
@ -4506,7 +4659,7 @@ dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"tokio",
"tracing",
]
@ -4550,7 +4703,7 @@ version = "0.1.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9cf6a813d3f40c88b0b6b6f29a5c95c6cdbf97c1f9cc53fb820200f5ad814d"
dependencies = [
"pin-project-lite 0.2.9",
"pin-project-lite 0.2.13",
"tracing-attributes",
"tracing-core",
]
@ -5124,19 +5277,6 @@ dependencies = [
"windows_x86_64_msvc 0.32.0",
]
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc 0.36.1",
"windows_i686_gnu 0.36.1",
"windows_i686_msvc 0.36.1",
"windows_x86_64_gnu 0.36.1",
"windows_x86_64_msvc 0.36.1",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
@ -5173,12 +5313,6 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
@ -5191,12 +5325,6 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
@ -5209,12 +5337,6 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
@ -5227,12 +5349,6 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
@ -5251,12 +5367,6 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"

@ -77,6 +77,7 @@ zip = "0.5"
bitcoin-harness = "0.2.2"
get-port = "3"
hyper = "0.14"
mockito = "1.1.0"
monero-harness = { path = "../monero-harness" }
port_check = "0.1"
proptest = "1"

@ -521,7 +521,7 @@ async fn init_bitcoin_wallet(
async fn init_monero_wallet(
data_dir: PathBuf,
monero_daemon_address: String,
monero_daemon_address: Option<String>,
env_config: Config,
) -> Result<(monero::Wallet, monero::WalletRpcProcess)> {
let network = env_config.monero_network;
@ -531,7 +531,7 @@ async fn init_monero_wallet(
let monero_wallet_rpc = monero::WalletRpc::new(data_dir.join("monero")).await?;
let monero_wallet_rpc_process = monero_wallet_rpc
.run(network, monero_daemon_address.as_str())
.run(network, monero_daemon_address)
.await?;
let monero_wallet = monero::Wallet::open_or_create(

@ -14,10 +14,6 @@ use structopt::{clap, StructOpt};
use url::Url;
use uuid::Uuid;
// See: https://moneroworld.com/
pub const DEFAULT_MONERO_DAEMON_ADDRESS: &str = "node.community.rino.io:18081";
pub const DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET: &str = "stagenet.community.rino.io:38081";
// See: https://1209k.com/bitcoin-eye/ele.php?chain=btc
const DEFAULT_ELECTRUM_RPC_URL: &str = "ssl://blockstream.info:700";
// See: https://1209k.com/bitcoin-eye/ele.php?chain=tbtc
@ -80,11 +76,11 @@ where
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
let monero_receive_address =
validate_monero_address(monero_receive_address, is_testnet)?;
let bitcoin_change_address =
validate_bitcoin_address(bitcoin_change_address, is_testnet)?;
let monero_daemon_address = monero.monero_daemon_address;
Arguments {
env_config: env_config_from(is_testnet),
@ -167,7 +163,7 @@ where
} => {
let (bitcoin_electrum_rpc_url, bitcoin_target_block) =
bitcoin.apply_defaults(is_testnet)?;
let monero_daemon_address = monero.apply_defaults(is_testnet);
let monero_daemon_address = monero.monero_daemon_address;
Arguments {
env_config: env_config_from(is_testnet),
@ -254,7 +250,7 @@ pub enum Command {
bitcoin_target_block: usize,
bitcoin_change_address: bitcoin::Address,
monero_receive_address: monero::Address,
monero_daemon_address: String,
monero_daemon_address: Option<String>,
tor_socks5_port: u16,
namespace: XmrBtcNamespace,
},
@ -274,7 +270,7 @@ pub enum Command {
swap_id: Uuid,
bitcoin_electrum_rpc_url: Url,
bitcoin_target_block: usize,
monero_daemon_address: String,
monero_daemon_address: Option<String>,
tor_socks5_port: u16,
namespace: XmrBtcNamespace,
},
@ -436,23 +432,11 @@ enum RawCommand {
struct Monero {
#[structopt(
long = "monero-daemon-address",
help = "Specify to connect to a monero daemon of your choice: <host>:<port>"
help = "Specify to connect to a monero daemon of your choice: <host>:<port>. If none is specified, we will connect to a public node."
)]
monero_daemon_address: Option<String>,
}
impl Monero {
fn apply_defaults(self, testnet: bool) -> String {
if let Some(address) = self.monero_daemon_address {
address
} else if testnet {
DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string()
} else {
DEFAULT_MONERO_DAEMON_ADDRESS.to_string()
}
}
}
#[derive(structopt::StructOpt, Debug)]
struct Bitcoin {
#[structopt(long = "electrum-rpc", help = "Provide the Bitcoin Electrum RPC URL")]
@ -1174,7 +1158,7 @@ mod tests {
bitcoin_change_address: BITCOIN_TESTNET_ADDRESS.parse().unwrap(),
monero_receive_address: monero::Address::from_str(MONERO_STAGENET_ADDRESS)
.unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
monero_daemon_address: None,
tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Testnet,
},
@ -1194,7 +1178,7 @@ mod tests {
bitcoin_change_address: BITCOIN_MAINNET_ADDRESS.parse().unwrap(),
monero_receive_address: monero::Address::from_str(MONERO_MAINNET_ADDRESS)
.unwrap(),
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
monero_daemon_address: None,
tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Mainnet,
},
@ -1212,7 +1196,7 @@ mod tests {
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL_TESTNET)
.unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(),
monero_daemon_address: None,
tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Testnet,
},
@ -1229,7 +1213,7 @@ mod tests {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
bitcoin_electrum_rpc_url: Url::from_str(DEFAULT_ELECTRUM_RPC_URL).unwrap(),
bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET,
monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(),
monero_daemon_address: None,
tor_socks5_port: DEFAULT_SOCKS5_PORT,
namespace: XmrBtcNamespace::Mainnet,
},

@ -1,19 +1,45 @@
use ::monero::Network;
use anyhow::{Context, Result};
use anyhow::{bail, Context, Error, Result};
use big_bytes::BigByte;
use futures::{StreamExt, TryStreamExt};
use monero_rpc::wallet::{Client, MoneroWalletRpc as _};
use reqwest::header::CONTENT_LENGTH;
use reqwest::Url;
use serde::Deserialize;
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
use std::io::ErrorKind;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::time::Duration;
use tokio::fs::{remove_file, OpenOptions};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::process::{Child, Command};
use tokio_util::codec::{BytesCodec, FramedRead};
use tokio_util::io::StreamReader;
// See: https://www.moneroworld.com/#nodes, https://monero.fail
// We don't need any testnet nodes because we don't support testnet at all
const MONERO_DAEMONS: [MoneroDaemon; 17] = [
MoneroDaemon::new("xmr-node.cakewallet.com", 18081, Network::Mainnet),
MoneroDaemon::new("nodex.monerujo.io", 18081, Network::Mainnet),
MoneroDaemon::new("node.moneroworld.com", 18089, Network::Mainnet),
MoneroDaemon::new("nodes.hashvault.pro", 18081, Network::Mainnet),
MoneroDaemon::new("p2pmd.xmrvsbeast.com", 18081, Network::Mainnet),
MoneroDaemon::new("node.monerodevs.org", 18089, Network::Mainnet),
MoneroDaemon::new("xmr-node-usa-east.cakewallet.com", 18081, Network::Mainnet),
MoneroDaemon::new("xmr-node-uk.cakewallet.com", 18081, Network::Mainnet),
MoneroDaemon::new("node.community.rino.io", 18081, Network::Mainnet),
MoneroDaemon::new("testingjohnross.com", 20031, Network::Mainnet),
MoneroDaemon::new("xmr.litepay.ch", 18081, Network::Mainnet),
MoneroDaemon::new("node.trocador.app", 18089, Network::Mainnet),
MoneroDaemon::new("stagenet.xmr-tw.org", 38081, Network::Stagenet),
MoneroDaemon::new("node.monerodevs.org", 38089, Network::Stagenet),
MoneroDaemon::new("singapore.node.xmr.pm", 38081, Network::Stagenet),
MoneroDaemon::new("xmr-lux.boldsuck.org", 38081, Network::Stagenet),
MoneroDaemon::new("stagenet.community.rino.io", 38081, Network::Stagenet),
];
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
compile_error!("unsupported operating system");
@ -50,6 +76,91 @@ pub struct WalletRpcProcess {
port: u16,
}
struct MoneroDaemon {
address: &'static str,
port: u16,
network: Network,
}
impl MoneroDaemon {
const fn new(address: &'static str, port: u16, network: Network) -> Self {
Self {
address,
port,
network,
}
}
/// Checks if the Monero daemon is available by sending a request to its `get_info` endpoint.
async fn is_available(&self, client: &reqwest::Client) -> Result<bool, Error> {
let url = format!("http://{}:{}/get_info", self.address, self.port);
let res = client
.get(url)
.send()
.await
.context("Failed to send request to get_info endpoint")?;
let json: MoneroDaemonGetInfoResponse = res
.json()
.await
.context("Failed to deserialize daemon get_info response")?;
let is_status_ok = json.status == "OK";
let is_synchronized = json.synchronized;
let is_correct_network = match self.network {
Network::Mainnet => json.mainnet,
Network::Stagenet => json.stagenet,
Network::Testnet => json.testnet,
};
Ok(is_status_ok && is_synchronized && is_correct_network)
}
}
impl Display for MoneroDaemon {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.address, self.port)
}
}
#[derive(Deserialize)]
struct MoneroDaemonGetInfoResponse {
status: String,
synchronized: bool,
mainnet: bool,
stagenet: bool,
testnet: bool,
}
/// Chooses an available Monero daemon based on the specified network.
async fn choose_monero_daemon(network: Network) -> Result<&'static MoneroDaemon, Error> {
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(30))
.https_only(false)
.build()?;
// We only want to check for daemons that match the specified network
let network_matching_daemons = MONERO_DAEMONS
.iter()
.filter(|daemon| daemon.network == network);
for daemon in network_matching_daemons {
match daemon.is_available(&client).await {
Ok(true) => {
tracing::debug!(%daemon, "Found available Monero daemon");
return Ok(daemon);
}
Err(err) => {
tracing::debug!(%err, %daemon, "Failed to connect to Monero daemon");
continue;
}
Ok(false) => continue,
}
}
bail!("No Monero daemon could be found. Please specify one manually or try again later.")
}
impl WalletRpcProcess {
pub fn endpoint(&self) -> Url {
Url::parse(&format!("http://127.0.0.1:{}/json_rpc", self.port))
@ -153,13 +264,23 @@ impl WalletRpc {
Ok(monero_wallet_rpc)
}
pub async fn run(&self, network: Network, daemon_address: &str) -> Result<WalletRpcProcess> {
pub async fn run(
&self,
network: Network,
daemon_address: Option<String>,
) -> Result<WalletRpcProcess> {
let port = tokio::net::TcpListener::bind("127.0.0.1:0")
.await?
.local_addr()?
.port();
let daemon_address = match daemon_address {
Some(daemon_address) => daemon_address,
None => choose_monero_daemon(network).await?.to_string(),
};
tracing::debug!(
%daemon_address,
%port,
"Starting monero-wallet-rpc"
);
@ -232,7 +353,6 @@ impl WalletRpc {
#[cfg(not(target_os = "windows"))]
async fn extract_archive(monero_wallet_rpc: &Self) -> Result<()> {
use anyhow::bail;
use tokio_tar::Archive;
let mut options = OpenOptions::new();
@ -297,3 +417,123 @@ impl WalletRpc {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn extract_host_and_port(address: String) -> (&'static str, u16) {
let parts: Vec<&str> = address.split(':').collect();
if parts.len() == 2 {
let host = parts[0].to_string();
let port = parts[1].parse::<u16>().unwrap();
let static_str_host: &'static str = Box::leak(host.into_boxed_str());
return (static_str_host, port);
}
panic!("Could not extract host and port from address: {}", address)
}
#[tokio::test]
async fn test_is_daemon_available_success() {
let mut server = mockito::Server::new();
let _ = server
.mock("GET", "/get_info")
.with_status(200)
.with_body(
r#"
{
"status": "OK",
"synchronized": true,
"mainnet": true,
"stagenet": false,
"testnet": false
}
"#,
)
.create();
let (host, port) = extract_host_and_port(server.host_with_port());
let client = reqwest::Client::new();
let result = MoneroDaemon::new(host, port, Network::Mainnet)
.is_available(&client)
.await;
assert!(result.is_ok());
assert!(result.unwrap());
}
#[tokio::test]
async fn test_is_daemon_available_wrong_network_failure() {
let mut server = mockito::Server::new();
let _ = server
.mock("GET", "/get_info")
.with_status(200)
.with_body(
r#"
{
"status": "OK",
"synchronized": true,
"mainnet": true,
"stagenet": false,
"testnet": false
}
"#,
)
.create();
let (host, port) = extract_host_and_port(server.host_with_port());
let client = reqwest::Client::new();
let result = MoneroDaemon::new(host, port, Network::Stagenet)
.is_available(&client)
.await;
assert!(result.is_ok());
assert!(!result.unwrap());
}
#[tokio::test]
async fn test_is_daemon_available_not_synced_failure() {
let mut server = mockito::Server::new();
let _ = server
.mock("GET", "/get_info")
.with_status(200)
.with_body(
r#"
{
"status": "OK",
"synchronized": false,
"mainnet": true,
"stagenet": false,
"testnet": false
}
"#,
)
.create();
let (host, port) = extract_host_and_port(server.host_with_port());
let client = reqwest::Client::new();
let result = MoneroDaemon::new(host, port, Network::Mainnet)
.is_available(&client)
.await;
assert!(result.is_ok());
assert!(!result.unwrap());
}
#[tokio::test]
async fn test_is_daemon_available_network_error_failure() {
let client = reqwest::Client::new();
let result = MoneroDaemon::new("does.not.exist.com", 18081, Network::Mainnet)
.is_available(&client)
.await;
assert!(result.is_err());
}
}

Loading…
Cancel
Save