7 Commits

Author SHA1 Message Date
ardocrat 6835bb1909 fix: do not send over tor when service not launched 2026-04-10 00:28:27 +03:00
ardocrat 31bc74529c build: update grin node 2026-04-09 20:56:45 +03:00
ardocrat 8d6943975b gui: glow renderer by default 2026-04-09 02:44:06 +03:00
ardocrat 4c5d8abe7b wix: update uuid 2026-04-09 02:44:01 +03:00
ardocrat 4dc42bce4a tor: fix multiline bridge connection 2026-03-30 01:37:36 +03:00
ardocrat e2d5d92f18 build: version 0.3.3 2026-03-30 01:36:45 +03:00
ardocrat b001eb4712 node: update to last git version (fix pibd stuck) 2026-03-29 21:18:36 +03:00
13 changed files with 93 additions and 61 deletions
Generated
+1 -1
View File
@@ -4000,7 +4000,7 @@ dependencies = [
[[package]]
name = "grim"
version = "0.3.2"
version = "0.3.3"
dependencies = [
"android-activity",
"android_logger",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "grim"
version = "0.3.2"
version = "0.3.3"
authors = ["Ardocrat <ardocrat@gri.mw>"]
description = "Cross-platform GUI for Grin with focus on usability and availability to be used by anyone, anywhere."
license = "Apache-2.0"
+1 -1
View File
@@ -12,7 +12,7 @@ android {
minSdk 24
targetSdk 36
versionCode 5
versionName "0.3.2"
versionName "0.3.3"
}
lint {
+1 -1
View File
@@ -21,7 +21,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.3.2</string>
<string>0.3.3</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
+1 -1
Submodule node updated: 2ec7b4d5cd...42b928a42f
+1 -1
View File
@@ -242,7 +242,7 @@ impl WalletTransactionsContent {
});
}
// Draw button to repeat transaction action.
if tx.can_repeat_action() || repeat {
if tx.can_repeat_action(wallet) || repeat {
Self::tx_repeat_button_ui(ui, CornerRadius::default(), tx, wallet, repeat);
}
}
+1 -1
View File
@@ -305,7 +305,7 @@ impl WalletTransactionContent {
});
}
// Draw button to repeat transaction action.
if tx.can_repeat_action() || repeat {
if tx.can_repeat_action(wallet) || repeat {
let r = if tx.can_finalize() || tx.can_cancel() {
CornerRadius::default()
} else {
+2 -12
View File
@@ -95,14 +95,8 @@ fn start_desktop_gui(platform: grim::gui::platform::Desktop) {
.with_transparent(true)
.with_decorations(is_mac || is_win);
let renderer = if is_mac {
eframe::Renderer::Glow
} else {
eframe::Renderer::Wgpu
};
let mut options = eframe::NativeOptions {
renderer,
renderer: eframe::Renderer::Glow,
viewport,
..Default::default()
};
@@ -113,11 +107,7 @@ fn start_desktop_gui(platform: grim::gui::platform::Desktop) {
Ok(_) => {}
Err(_) => {
// Start with another renderer on error.
if is_mac {
options.renderer = eframe::Renderer::Wgpu;
} else {
options.renderer = eframe::Renderer::Glow;
}
options.renderer = eframe::Renderer::Wgpu;
let app = grim::gui::App::new(platform);
match grim::start(options, grim::app_creator(app)) {
+47 -26
View File
@@ -101,25 +101,32 @@ impl Default for Tor {
impl Tor {
/// Create Tor configuration returning unused bridges (exclude more than 2 to avoid stuck).
fn build_config(bridges: Option<Vec<TorBridge>>) -> (TorClientConfig, Vec<TorBridge>) {
fn build_config(bridges: Option<Vec<TorBridge>>)
-> (TorClientConfig, Vec<TorBridge>, Vec<TorBridge>) {
let mut builder = TorClientConfigBuilder::from_directories(
TorConfig::state_path(),
TorConfig::cache_path(),
);
// Build bridges.
let bridges = bridges.unwrap_or(vec![]);
let mut bridges = bridges.unwrap_or(vec![]);
let max_two_bridges = if bridges.len() > 2 {
bridges.iter().take(2).map(|b| b.clone()).collect::<Vec<TorBridge>>()
let two_bridges = bridges.iter().take(2)
.cloned()
.collect::<Vec<TorBridge>>();
bridges = bridges.iter().filter(|b| !two_bridges.contains(b))
.cloned()
.collect::<Vec<TorBridge>>();
two_bridges
} else {
bridges.clone()
};
for b in max_two_bridges {
for b in max_two_bridges.clone() {
Self::build_bridge(&mut builder, b);
}
builder.address_filter().allow_onion_addrs(true);
// Create config.
let config = builder.build().unwrap();
(config, bridges.iter().map(|b| b.clone()).collect::<Vec<TorBridge>>())
(config, bridges, max_two_bridges)
}
/// Build bootstrapped client from provided config.
@@ -175,15 +182,14 @@ impl Tor {
// Get initial bridges.
let initial_bridges = if let Some(b) = TorConfig::get_bridge() {
let lines_parse = serde_json::from_str::<Vec<String>>(&b.connection_line());
let bridges = if let Ok(lines) = lines_parse {
lines.iter()
.map(|l| TorBridge::Webtunnel(b.binary_path(), l.clone()))
.collect()
} else {
b.connection_line().lines()
.map(|l| TorBridge::Webtunnel(b.binary_path(), l.to_string()))
.collect()
};
let bridges = lines_parse.unwrap_or_else(|_| b.connection_line()
.lines()
.map(|l| l.to_string()).collect()
).iter().map(|l| {
let mut bridge = b.clone();
bridge.update_conn_line(l.clone());
bridge
}).collect::<Vec<TorBridge>>();
Some(bridges)
} else {
None
@@ -192,19 +198,39 @@ impl Tor {
let mut default_attempt = false;
let mut config_bridges = Self::build_config(initial_bridges);
loop {
let (config, unused_bridges) = config_bridges.clone();
let (config, unused_bridges, used_bridges) = config_bridges.clone();
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
// Update bridges order.
if let Some(b) = TorConfig::get_bridge() {
let lines_parse = serde_json::from_str::<Vec<String>>(&b.connection_line());
match lines_parse {
Ok(mut lines) => {
lines.sort_by_key(|l| {
let mut bridge = b.clone();
bridge.update_conn_line(l.clone());
!used_bridges.contains(&bridge)
});
let lines_str = serde_json::to_string(&lines)
.unwrap_or_else(|_| {
TorConfig::default_webtunnel_bridge().connection_line()
});
TorBridge::save_bridge_conn_line(&b, lines_str);
}
Err(_) => {},
}
}
TOR_STATE.client_config.write().replace((c, config.clone()));
break;
} else {
// Cleanup state and cache.
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
// Check unused bridges to check another part.
if !unused_bridges.is_empty() {
config_bridges = Self::build_config(Some(unused_bridges));
continue;
}
// Cleanup state and cache.
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
if !default_attempt {
default_attempt = true;
// Launch client with default Webtunnel bridges if failed.
@@ -214,11 +240,8 @@ impl Tor {
config_bridges = Self::build_config(Some(add_bridges));
continue;
} else if TorConfig::get_bridge().is_some() {
// Cleanup state and cache.
fs::remove_dir_all(TorConfig::state_path()).unwrap_or_default();
fs::remove_dir_all(TorConfig::cache_path()).unwrap_or_default();
// Launch without bridges if all attempts failed.
let (config, _) = Self::build_config(None);
let (config, _, _) = Self::build_config(None);
let client = Self::build_client_bootstrap(config.clone());
if let Some(c) = client {
TOR_STATE.client_config.write().replace((c, config));
@@ -279,10 +302,8 @@ impl Tor {
return None;
}
}
// Launch client if needed.
Self::launch();
if Self::client_config().is_none() {
error!("Tor: can not launch Tor client");
error!("Tor: client not launched");
return None;
}
// Create http tor-powered client to post data.
@@ -557,7 +578,7 @@ impl Tor {
const MAX_ERRORS: i32 = 16;
let mut errors_count = 0;
// Wait 5 seconds.
thread::sleep(Duration::from_millis(5000));
tokio::time::sleep(Duration::from_millis(5000)).await;
loop {
if !Self::check_running(&service_id) {
break;
+24 -9
View File
@@ -41,7 +41,7 @@ impl TorProxy {
}
/// Tor network bridge type.
#[derive(Serialize, Deserialize, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub enum TorBridge {
/// Obfs4 bridge with binary path and connection line.
Webtunnel(String, String),
@@ -59,13 +59,13 @@ impl TorBridge {
/// Default webtunnel protocol connection line.
pub const DEFAULT_WEBTUNNEL_CONN_LINE: &'static str = "webtunnel [2001:db8:beb:5884:ffcc:bfe3:2858:b06b]:443 1E242C749707B4A68A269F0D31311CE36CDFEC28 url=https://wt.gri.mw/74Fm0lKUWWMMjZpKf6iSC0UH";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_1: &'static str = "webtunnel [2001:db8:f1c4:ca39:40a2:2e3f:f66b:2308]:443 93557BF013203581B6B7C3BF016425F1758F7CD6 url=https://diffusesystems.net/UvVD4kzlcS8HLlpxDdRWXidiDTDt0EiZ ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_2: &'static str = "webtunnel [2001:db8:eedb:cae7:a345:4f72:f9cc:5de0]:443 B3C81E7A0CA474270DAA4A2C8633E1CA8935C37D url=https://wordpress.far-east-investment.ru/sORes7268CEUSRD7hAWvJU5A ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_3: &'static str = "webtunnel [2001:db8:945c:e0b9:7e4c:c974:ff00:d4c5]:443 91937F3EFB3BE5169788AC7C8BF07460B7E306DB url=https://kabel.entreri.de/YXbp1dNrJeOF8giAFFYWxvmf ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_4: &'static str = "webtunnel [2001:db8:4767:7aa2:df21:1b2b:d7f9:caee]:443 CD193CF0D0C29551928C01FCB28D1200D9F27CFA url=https://occurrence.pics/68SzSlQCRgnfSo32eLyjC1V3 ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:ce90:3593:272e:4975:a031:55b]:443 12382A2F3912AD1983A97C8709CBAE47ADB60BE3 url=https://miranda.today/LWwxIXDHCyyScn7oDauPMTmX ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_6: &'static str = "webtunnel [2001:db8:a12b:ff8:8a1a:a05b:5f21:2ccc]:443 F2A9C5AEE0A420EB9D55F9497B3C0FA243A2A770 url=https://bridge.lovecloud.me/wss-wc3p0euqrlne98t9 ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_7: &'static str = "webtunnel [2001:db8:8ed6:e6c9:5fc9:9f20:a373:2374]:443 1636A2EFFBAA4B162F5FF461A1663EB55C41AE11 url=https://hanoi.delivery/roQFPLtlspWT6yIKeXD6lEci ver=0.0.3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_1: &'static str = "webtunnel [2001:db8:1640:379c:ad30:db5f:bff5:37d0]:443 AF8F7548C886D6F53A652411DBB71D089517085A url=https://app05.oneclickhost.eu/alpfZGTB9FckCgOkOOA0OHlh";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_2: &'static str = "webtunnel [2001:db8:eedb:cae7:a345:4f72:f9cc:5de0]:443 B3C81E7A0CA474270DAA4A2C8633E1CA8935C37D url=https://wordpress.far-east-investment.ru/sORes7268CEUSRD7hAWvJU5A";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_3: &'static str = "webtunnel [2001:db8:945c:e0b9:7e4c:c974:ff00:d4c5]:443 91937F3EFB3BE5169788AC7C8BF07460B7E306DB url=https://kabel.entreri.de/YXbp1dNrJeOF8giAFFYWxvmf";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_4: &'static str = "webtunnel [2001:db8:4767:7aa2:df21:1b2b:d7f9:caee]:443 CD193CF0D0C29551928C01FCB28D1200D9F27CFA url=https://occurrence.pics/68SzSlQCRgnfSo32eLyjC1V3";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_5: &'static str = "webtunnel [2001:db8:ce90:3593:272e:4975:a031:55b]:443 12382A2F3912AD1983A97C8709CBAE47ADB60BE3 url=https://miranda.today/LWwxIXDHCyyScn7oDauPMTmX";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_6: &'static str = "webtunnel [2001:db8:a12b:ff8:8a1a:a05b:5f21:2ccc]:443 F2A9C5AEE0A420EB9D55F9497B3C0FA243A2A770 url=https://bridge.lovecloud.me/wss-wc3p0euqrlne98t9";
pub const ADDITIONAL_WEBTUNNEL_CONN_LINE_7: &'static str = "webtunnel [2001:db8:8ed6:e6c9:5fc9:9f20:a373:2374]:443 1636A2EFFBAA4B162F5FF461A1663EB55C41AE11 url=https://hanoi.delivery/roQFPLtlspWT6yIKeXD6lEci";
pub const DEFAULT_WEBTUNNEL_CONN_LINES: [&'static str; 8] = [
TorBridge::DEFAULT_WEBTUNNEL_CONN_LINE,
@@ -79,7 +79,7 @@ impl TorBridge {
];
/// Default Obfs4 protocol connection line.
pub const DEFAULT_OBFS4_CONN_LINE: &'static str = "obfs4 45.76.43.226:3479 7AAFDC594147E72635DD64DB47A8CD8781F463F6 cert=bJ720bjXkmFGGAD77BsCMopkDzQ/cXDj0QntOmsBYw7Fqohq7Y7yZMV7FlECQNB1tyq1AA iat-mode=0";
pub const DEFAULT_OBFS4_CONN_LINE: &'static str = "obfs4 51.83.248.35:25981 D08B4760D128C1A65506577E063D9D26C2A71815 cert=UJWUh+sIDdOKja/byBM2+qP9AFNl86hkGRFJ/lM1GWKP79eCu3PT4WTXI2gdXYULbQ0EMg iat-mode=0";
/// Default Snowflake protocol connection line.
pub const DEFAULT_SNOWFLAKE_CONN_LINE: &'static str = "snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://1098762253.rsc.cdn77.org/ fronts=www.cdn77.com,www.phpmyadmin.net ice=stun:stun.l.google.com:19302,stun:stun.antisip.com:3478,stun:stun.bluesip.net:3478,stun:stun.dus.net:3478,stun:stun.epygi.com:3478,stun:stun.sonetel.net:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.voys.nl:3478 utls-imitate=hellorandomizedalpn";
@@ -106,6 +106,12 @@ impl TorBridge {
}
}
/// Get bridge client binary name.
pub fn binary_name(&self) -> String {
let path = self.binary_path();
path.split(std::path::MAIN_SEPARATOR_STR).last().unwrap().to_string()
}
/// Get bridge client connection line.
pub fn connection_line(&self) -> String {
match self {
@@ -115,6 +121,15 @@ impl TorBridge {
}
}
/// Update bridge connection line.
pub fn update_conn_line(&mut self, l: String) {
*self = match TorConfig::get_bridge().unwrap() {
TorBridge::Webtunnel(bin, _) => TorBridge::Webtunnel(bin, l.clone()),
TorBridge::Obfs4(bin, _) => TorBridge::Obfs4(bin, l.clone()),
TorBridge::Snowflake(bin, _) => TorBridge::Snowflake(bin, l.clone()),
};
}
/// Save binary path to provided bridge.
pub fn save_bridge_bin_path(bridge: &TorBridge, path: String) {
match bridge {
+4 -2
View File
@@ -20,6 +20,7 @@ use grin_wallet_util::OnionV3Address;
use serde_derive::{Deserialize, Serialize};
use std::sync::Arc;
use crate::tor::Tor;
use crate::wallet::Wallet;
/// Mnemonic phrase word.
@@ -377,12 +378,13 @@ impl WalletTx {
}
/// Check if possible to repeat transaction action.
pub fn can_repeat_action(&self) -> bool {
pub fn can_repeat_action(&self, wallet: &Wallet) -> bool {
if let Some(a) = &self.action {
self.action_error.is_some() && a != &WalletTxAction::Cancelling
} else {
// Can resend over Tor.
!self.data.confirmed && !self.sending_tor() && !self.broadcasting() &&
!self.data.confirmed && !self.sending_tor() &&
Tor::is_service_running(&wallet.identifier()) && !self.broadcasting() &&
self.receiver.is_some()
}
}
+7 -3
View File
@@ -1735,9 +1735,13 @@ async fn handle_task(w: &Wallet, t: WalletTask) {
let tx = w.retrieve_tx_by_id(None, Some(s.id));
if let Some(tx) = tx {
if let Some(addr) = r {
w.send_creating.store(false, Ordering::Relaxed);
send_tor(tx, &s, addr).await;
return;
if Tor::is_service_running(&w.identifier()) {
w.send_creating.store(false, Ordering::Relaxed);
send_tor(tx, &s, addr).await;
return;
} else {
w.on_task_result(Some(tx), &t);
}
} else {
w.on_task_result(Some(tx), &t);
}
+2 -2
View File
@@ -7,8 +7,8 @@
<?endif ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Version="0.3.2" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Language="1033" Name="Grim" Manufacturer="Ardocrat">
<Package Id="4E02367F-B87C-4CE7-9724-9E67C203DADD" InstallerVersion="300" Compressed="yes"/>
<Product Id="*" Version="0.3.3" UpgradeCode="C19F9B41-CD13-4F0E-B27D-E0EF8CF1CE91" Language="1033" Name="Grim" Manufacturer="Ardocrat">
<Package Id="F0DD07CB-48B4-419C-9A20-CE41CD0D9252" InstallerVersion="300" Compressed="yes"/>
<Media Id="1" Cabinet="grim.cab" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades = "yes"/>