Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/backend_task/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,26 @@ mod refresh_wallet_info;
mod start_dash_qt;

use crate::backend_task::BackendTaskSuccessResult;
use crate::config::Config;
use crate::context::AppContext;
use crate::model::wallet::Wallet;
use dash_sdk::dashcore_rpc::RpcApi;
use dash_sdk::dashcore_rpc::{Auth, Client};
use dash_sdk::dpp::dashcore::{Address, ChainLock, Network, OutPoint, Transaction, TxOut};
use std::sync::{Arc, RwLock};

#[derive(Debug, Clone)]
pub(crate) enum CoreTask {
GetBestChainLock,
GetBestChainLocks,
RefreshWalletInfo(Arc<RwLock<Wallet>>),
StartDashQT(Network, Option<String>, bool),
}
impl PartialEq for CoreTask {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(CoreTask::GetBestChainLock, CoreTask::GetBestChainLock) => true,
(CoreTask::GetBestChainLocks, CoreTask::GetBestChainLocks) => true,
(CoreTask::RefreshWalletInfo(_), CoreTask::RefreshWalletInfo(_)) => true,
(CoreTask::StartDashQT(_, _, _), CoreTask::StartDashQT(_, _, _)) => true,
_ => false,
Expand All @@ -29,6 +33,7 @@ impl PartialEq for CoreTask {
pub(crate) enum CoreItem {
ReceivedAvailableUTXOTransaction(Transaction, Vec<(OutPoint, TxOut, Address)>),
ChainLock(ChainLock, Network),
ChainLocks(Option<ChainLock>, Option<ChainLock>), // Mainnet, Testnet
}

impl AppContext {
Expand All @@ -44,6 +49,87 @@ impl AppContext {
))
})
.map_err(|e| e.to_string()),
CoreTask::GetBestChainLocks => {
tracing::info!("Getting best chain locks for testnet and mainnet");

// Load configs
let config = match Config::load() {
Ok(config) => config,
Err(e) => {
return Err(format!("Failed to load config: {}", e));
}
};
let maybe_mainnet_config = config.config_for_network(Network::Dash);
let maybe_testnet_config = config.config_for_network(Network::Testnet);

// Get mainnet best chainlock
let mainnet_result = if let Some(mainnet_config) = maybe_mainnet_config {
let mainnet_addr = format!(
"http://{}:{}",
mainnet_config.core_host, mainnet_config.core_rpc_port
);
let mainnet_client = Client::new(
&mainnet_addr,
Auth::UserPass(
mainnet_config.core_rpc_user.to_string(),
mainnet_config.core_rpc_password.to_string(),
),
)
.map_err(|_| "Failed to create mainnet client".to_string())?;
mainnet_client.get_best_chain_lock().map_err(|e| {
format!(
"Failed to get best chain lock for mainnet: {}",
e.to_string()
)
})
} else {
Err("Mainnet config not found".to_string())
};

// Get testnet best chainlock
let testnet_result = if let Some(testnet_config) = maybe_testnet_config {
let testnet_addr = format!(
"http://{}:{}",
testnet_config.core_host, testnet_config.core_rpc_port
);
let testnet_client = Client::new(
&testnet_addr,
Auth::UserPass(
testnet_config.core_rpc_user.to_string(),
testnet_config.core_rpc_password.to_string(),
),
)
.map_err(|_| "Failed to create testnet client".to_string())?;
testnet_client.get_best_chain_lock().map_err(|e| {
format!(
"Failed to get best chain lock for testnet: {}",
e.to_string()
)
})
} else {
Err("Testnet config not found".to_string())
};

// Handle results
match (mainnet_result, testnet_result) {
(Ok(mainnet_chainlock), Ok(testnet_chainlock)) => {
Ok(BackendTaskSuccessResult::CoreItem(CoreItem::ChainLocks(
Some(mainnet_chainlock),
Some(testnet_chainlock),
)))
}
(Ok(mainnet_chainlock), Err(_)) => Ok(BackendTaskSuccessResult::CoreItem(
CoreItem::ChainLocks(Some(mainnet_chainlock), None),
)),
(Err(_), Ok(testnet_chainlock)) => Ok(BackendTaskSuccessResult::CoreItem(
CoreItem::ChainLocks(None, Some(testnet_chainlock)),
)),
(Err(_), Err(_)) => {
Err("Failed to get best chain lock for both mainnet and testnet"
.to_string())
}
}
}
CoreTask::RefreshWalletInfo(wallet) => self.refresh_wallet_info(wallet),
CoreTask::StartDashQT(network, custom_dash_qt, overwrite_dash_conf) => self
.start_dash_qt(network, custom_dash_qt, overwrite_dash_conf)
Expand Down
95 changes: 44 additions & 51 deletions src/ui/network_chooser_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ use crate::app::AppAction;
use crate::backend_task::core::{CoreItem, CoreTask};
use crate::backend_task::{BackendTask, BackendTaskSuccessResult};
use crate::context::AppContext;
use crate::model::password_info::PasswordInfo;
use crate::ui::components::left_panel::add_left_panel;
use crate::ui::components::top_panel::add_top_panel;
use crate::ui::wallet::add_new_wallet_screen::AddNewWalletScreen;
use crate::ui::{RootScreenType, Screen, ScreenLike};
use dash_sdk::dashcore_rpc::RpcApi;
use dash_sdk::dpp::dashcore::Network;
use dash_sdk::dpp::identity::TimestampMillis;
use eframe::egui::{self, Color32, Context, Ui};
Expand All @@ -20,7 +18,6 @@ pub struct NetworkChooserScreen {
pub current_network: Network,
pub mainnet_core_status_online: bool,
pub testnet_core_status_online: bool,
status_checked: bool,
pub recheck_time: Option<TimestampMillis>,
custom_dash_qt_path: Option<String>,
custom_dash_qt_error_message: Option<String>,
Expand All @@ -41,7 +38,6 @@ impl NetworkChooserScreen {
current_network,
mainnet_core_status_online: false,
testnet_core_status_online: false,
status_checked: false,
recheck_time: None,
custom_dash_qt_path,
custom_dash_qt_error_message: None,
Expand All @@ -63,11 +59,6 @@ impl NetworkChooserScreen {
self.context_for_network(self.current_network)
}

/// Function to check the status of Dash Core for a given network
async fn check_core_status(app_context: &Arc<AppContext>) -> bool {
app_context.core_client.get_best_chain_lock().is_ok()
}

/// Render the network selection table
fn render_network_table(&mut self, ui: &mut Ui) -> AppAction {
let mut app_action = AppAction::None;
Expand All @@ -85,10 +76,10 @@ impl NetworkChooserScreen {
ui.label("Start");
ui.end_row();

// Render Mainnet
// Render Mainnet Row
app_action |= self.render_network_row(ui, Network::Dash, "Mainnet");

// Render Testnet
// Render Testnet Row
app_action |= self.render_network_row(ui, Network::Testnet, "Testnet");
});
egui::CollapsingHeader::new("Show more advanced settings")
Expand Down Expand Up @@ -170,23 +161,11 @@ impl NetworkChooserScreen {
let mut app_action = AppAction::None;
ui.label(name);

// Simulate checking network status
// Check network status
let is_working = self.check_network_status(network);
let status_color = if is_working {
Color32::from_rgb(0, 255, 0) // Green if working
} else {
if let Some(recheck_time) = self.recheck_time {
let current_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
let current_time_ms = current_time.as_millis() as u64;
if current_time_ms >= recheck_time {
app_action |=
AppAction::BackendTask(BackendTask::CoreTask(CoreTask::GetBestChainLock));
self.recheck_time =
Some((current_time + Duration::from_secs(5)).as_millis() as u64);
}
}
Color32::from_rgb(255, 0, 0) // Red if not working
};

Expand Down Expand Up @@ -216,7 +195,7 @@ impl NetworkChooserScreen {
} else {
&self.testnet_app_context.as_ref().unwrap()
};
app_action |=
app_action =
AppAction::AddScreen(Screen::AddNewWalletScreen(AddNewWalletScreen::new(context)));
}

Expand All @@ -225,7 +204,7 @@ impl NetworkChooserScreen {
if ui.checkbox(&mut is_selected, "Select").clicked() && is_selected {
self.current_network = network;
app_action = AppAction::SwitchNetwork(network);
// in 1 second
// Recheck in 1 second
self.recheck_time = Some(
(SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand All @@ -237,26 +216,18 @@ impl NetworkChooserScreen {

// Add a button to start the network
if ui.button("Start").clicked() {
app_action |= AppAction::BackendTask(BackendTask::CoreTask(CoreTask::StartDashQT(
app_action = AppAction::BackendTask(BackendTask::CoreTask(CoreTask::StartDashQT(
network,
self.custom_dash_qt_path.clone(),
self.overwrite_dash_conf,
)));
// in 5 seconds
self.recheck_time = Some(
(SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
+ Duration::from_secs(5))
.as_millis() as u64,
);
}

ui.end_row();
app_action
}

/// Simulate a function to check if the network is working
/// Check if the network is working
fn check_network_status(&self, network: Network) -> bool {
match network {
Network::Dash => self.mainnet_core_status_online,
Expand All @@ -267,35 +238,40 @@ impl NetworkChooserScreen {
}

impl ScreenLike for NetworkChooserScreen {
fn display_message(&mut self, message: &str, _message_type: super::MessageType) {
if message.contains("Failed to get best chain lock for both mainnet and testnet") {
self.mainnet_core_status_online = false;
self.testnet_core_status_online = false;
}
Comment on lines +241 to +245

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid string matching for error handling

Relying on string matching in display_message is fragile. Consider using error types or codes for more robust error handling.

Propose defining a custom error type or variant and updating the method accordingly:

// Define a custom message type or error enum
enum Message {
    FailedToGetBestChainLock,
    // other variants...
}

fn display_message(&mut self, message: &Message, _message_type: super::MessageType) {
    match message {
        Message::FailedToGetBestChainLock => {
            self.mainnet_core_status_online = false;
            self.testnet_core_status_online = false;
        }
        // handle other messages...
    }
}

}

fn display_task_result(&mut self, backend_task_success_result: BackendTaskSuccessResult) {
if let BackendTaskSuccessResult::CoreItem(CoreItem::ChainLock(_, network)) =
backend_task_success_result
{
match network {
Network::Dash => {
self.mainnet_core_status_online = true;
match backend_task_success_result {
BackendTaskSuccessResult::CoreItem(CoreItem::ChainLocks(
mainnet_chainlock,
testnet_chainlock,
)) => {
match mainnet_chainlock {
Some(_) => self.mainnet_core_status_online = true,
None => self.mainnet_core_status_online = false,
}
Network::Testnet => {
self.testnet_core_status_online = true;
match testnet_chainlock {
Some(_) => self.testnet_core_status_online = true,
None => self.testnet_core_status_online = false,
}
_ => {}
}
_ => {}
}
}

fn ui(&mut self, ctx: &Context) -> AppAction {
//let _ = self.current_app_context().db.get_settings();
let mut action = add_top_panel(
ctx,
self.current_app_context(),
vec![("Dash Evo Tool", AppAction::None)],
vec![],
);

if !self.status_checked {
self.status_checked = true;
action |= AppAction::BackendTask(BackendTask::CoreTask(CoreTask::GetBestChainLock));
}

action |= add_left_panel(
ctx,
self.current_app_context(),
Expand All @@ -306,6 +282,23 @@ impl ScreenLike for NetworkChooserScreen {
action |= self.render_network_table(ui);
});

// Recheck both network status every 3 seconds
let recheck_time = Duration::from_secs(3);
if action == AppAction::None {
let current_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards");
if let Some(time) = self.recheck_time {
if current_time.as_millis() as u64 >= time {
action =
AppAction::BackendTask(BackendTask::CoreTask(CoreTask::GetBestChainLocks));
self.recheck_time = Some((current_time + recheck_time).as_millis() as u64);
}
} else {
self.recheck_time = Some((current_time + recheck_time).as_millis() as u64);
}
}

action
}
}