diff --git a/.cursor/.gitkeep b/.cursor/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/CHANGELOG.md b/CHANGELOG.md index 29c3edf8..281ea29f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- **Load Balancing & Reliability**: Introduced `monero-rpc-pool`, a load-balancing proxy for Monero RPC nodes that automatically discovers healthy nodes and routes requests to improve connection reliability. -- **ASB Configuration**: Added `monero_node_pool` boolean option to ASB config. When enabled, the ASB uses the internal Monero RPC pool instead of connecting directly to a single daemon URL, providing improved reliability and automatic failover across multiple Monero nodes. +## [2.3.0-beta] - 2025-06-19 + +- ASB + CLI + GUI: Introduce a load-balancing proxy for Monero RPC nodes that automatically discovers healthy nodes and routes requests to improve connection reliability. +- ASB: Added `monero_node_pool` boolean option to ASB config. When enabled, the ASB uses the internal Monero RPC pool instead of connecting directly to a single daemon URL, providing improved reliability and automatic failover across multiple Monero nodes. ## [2.2.0-beta.2] - 2025-06-17 diff --git a/Cargo.lock b/Cargo.lock index 53e21792..037cd076 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5932,8 +5932,6 @@ dependencies = [ "chrono", "clap 4.5.38", "dirs 5.0.1", - "futures", - "monero", "monero-rpc", "rand 0.8.5", "regex", @@ -5947,7 +5945,6 @@ dependencies = [ "tower-http 0.5.2", "tracing", "tracing-subscriber", - "typeshare", "url", "uuid", ] @@ -9596,7 +9593,7 @@ checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" [[package]] name = "swap" -version = "2.2.0-beta.2" +version = "" dependencies = [ "anyhow", "arti-client", @@ -9634,7 +9631,6 @@ dependencies = [ "monero", "monero-harness", "monero-rpc", - "monero-rpc-pool", "monero-sys", "once_cell", "pem", @@ -12141,10 +12137,9 @@ dependencies = [ [[package]] name = "unstoppableswap-gui-rs" -version = "2.2.0-beta.2" +version = "" dependencies = [ "anyhow", - "monero-rpc-pool", "rustls 0.23.27", "serde", "serde_json", diff --git a/monero-rpc-pool/.sqlx/query-132666c849bf0db14e50ef41f429e17b7c1afd21031edf3af40fadfb79ef2597.json b/monero-rpc-pool/.sqlx/query-132666c849bf0db14e50ef41f429e17b7c1afd21031edf3af40fadfb79ef2597.json index 5e53eb29..dbc4e29b 100644 --- a/monero-rpc-pool/.sqlx/query-132666c849bf0db14e50ef41f429e17b7c1afd21031edf3af40fadfb79ef2597.json +++ b/monero-rpc-pool/.sqlx/query-132666c849bf0db14e50ef41f429e17b7c1afd21031edf3af40fadfb79ef2597.json @@ -17,10 +17,7 @@ "parameters": { "Right": 1 }, - "nullable": [ - true, - true - ] + "nullable": [true, true] }, "hash": "132666c849bf0db14e50ef41f429e17b7c1afd21031edf3af40fadfb79ef2597" } diff --git a/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json b/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json index c3f40302..d208a702 100644 --- a/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json +++ b/monero-rpc-pool/.sqlx/query-3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23.json @@ -42,15 +42,7 @@ "parameters": { "Right": 0 }, - "nullable": [ - false, - false, - false, - false, - false, - false, - false - ] + "nullable": [false, false, false, false, false, false, false] }, "hash": "3e8f39a6ec4443cec6497672891d12bbf7c1d0aca061827740af88ced863ae23" } diff --git a/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json b/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json index 197ccffd..3e52d837 100644 --- a/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json +++ b/monero-rpc-pool/.sqlx/query-5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821.json @@ -12,9 +12,7 @@ "parameters": { "Right": 7 }, - "nullable": [ - false - ] + "nullable": [false] }, "hash": "5798d9589772742f074e0ecc2551a40d943bfb7ed2e295f09f12d77cb65ce821" } diff --git a/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json b/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json index 86cbba1d..af454eda 100644 --- a/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json +++ b/monero-rpc-pool/.sqlx/query-e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781.json @@ -12,9 +12,7 @@ "parameters": { "Right": 1 }, - "nullable": [ - true - ] + "nullable": [true] }, "hash": "e0865335c2dcb040a34e3f1305fe1a823d6fcde4a061def602cba30971817781" } diff --git a/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json b/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json index fb2e5879..0ab81591 100644 --- a/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json +++ b/monero-rpc-pool/.sqlx/query-ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8.json @@ -22,11 +22,7 @@ "parameters": { "Right": 2 }, - "nullable": [ - false, - true, - false - ] + "nullable": [false, true, false] }, "hash": "ffa1b76d20c86d6bea02bd03e5e7de159adbb7c7c0ef585ce4df9ec648bea7f8" } diff --git a/monero-rpc-pool/src/discovery.rs b/monero-rpc-pool/src/discovery.rs index 2c3522cd..4222070c 100644 --- a/monero-rpc-pool/src/discovery.rs +++ b/monero-rpc-pool/src/discovery.rs @@ -332,12 +332,12 @@ impl NodeDiscovery { for node_url in nodes.iter() { if let Ok(url) = url::Url::parse(node_url) { let scheme = url.scheme(); - + // Validate scheme - must be http or https if !matches!(scheme, "http" | "https") { continue; } - + // Validate host - must be non-empty let Some(host) = url.host_str() else { continue; @@ -345,7 +345,7 @@ impl NodeDiscovery { if host.is_empty() { continue; } - + // Validate port - must be present let Some(port) = url.port() else { continue; diff --git a/src-gui/src/renderer/components/pages/help/SettingsBox.tsx b/src-gui/src/renderer/components/pages/help/SettingsBox.tsx index 102f7053..daaa4863 100644 --- a/src-gui/src/renderer/components/pages/help/SettingsBox.tsx +++ b/src-gui/src/renderer/components/pages/help/SettingsBox.tsx @@ -352,34 +352,48 @@ function MoneroRpcPoolSetting() { function MoneroNodeUrlSetting() { const network = getNetwork(); const useMoneroRpcPool = useSettings((s) => s.useMoneroRpcPool); - const moneroNodeUrl = useSettings((s) => s.nodes[network][Blockchain.Monero][0] || ""); + const moneroNodeUrl = useSettings( + (s) => s.nodes[network][Blockchain.Monero][0] || "", + ); const nodeStatuses = useNodes((s) => s.nodes); const dispatch = useAppDispatch(); const [isRefreshing, setIsRefreshing] = useState(false); const currentNodes = useSettings((s) => s.nodes[network][Blockchain.Monero]); - + const handleNodeUrlChange = (newUrl: string) => { // Remove existing nodes and add the new one - currentNodes.forEach(node => { + currentNodes.forEach((node) => { dispatch(removeNode({ network, type: Blockchain.Monero, node })); }); - + if (newUrl.trim()) { - dispatch(addNode({ network, type: Blockchain.Monero, node: newUrl.trim() })); + dispatch( + addNode({ network, type: Blockchain.Monero, node: newUrl.trim() }), + ); } }; const handleRefreshStatus = async () => { // Don't refresh if pool is enabled or no node URL is configured if (!moneroNodeUrl || useMoneroRpcPool) return; - + setIsRefreshing(true); try { - const status = await getNodeStatus(moneroNodeUrl, Blockchain.Monero, network); - + const status = await getNodeStatus( + moneroNodeUrl, + Blockchain.Monero, + network, + ); + // Update the status in the store - dispatch(setStatus({ node: moneroNodeUrl, status, blockchain: Blockchain.Monero })); + dispatch( + setStatus({ + node: moneroNodeUrl, + status, + blockchain: Blockchain.Monero, + }), + ); } catch (error) { console.error("Failed to refresh node status:", error); } finally { @@ -388,7 +402,9 @@ function MoneroNodeUrlSetting() { }; const isValid = (url: string) => url === "" || isValidUrl(url, ["http"]); - const nodeStatus = moneroNodeUrl ? nodeStatuses[Blockchain.Monero][moneroNodeUrl] : null; + const nodeStatus = moneroNodeUrl + ? nodeStatuses[Blockchain.Monero][moneroNodeUrl] + : null; return ( @@ -416,26 +432,36 @@ function MoneroNodeUrlSetting() { noErrorWhenEmpty /> <> - + - + 0 ? moneroNodes[0] : null; diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 668ef034..09478e6a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "unstoppableswap-gui-rs" -version = "2.2.0-beta.2" +version = "2.3.0-beta" authors = [ "binarybaron", "einliterflasche", "unstoppableswap" ] edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 364eb4d3..9023d3b3 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "productName": "UnstoppableSwap", - "version": "2.2.0-beta.2", + "version": "2.3.0-beta", "identifier": "net.unstoppableswap.gui", "build": { "devUrl": "http://localhost:1420", diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 88e7c809..50ebb5bf 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap" -version = "2.2.0-beta.2" +version = "2.3.0-beta" authors = ["The COMIT guys "] edition = "2021" description = "XMR/BTC trustless atomic swaps."