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
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ sha2 = "0.10.8"
arboard = { version = "3.4.0", default-features = false, features = [
"windows-sys",
] }
enum_dispatch = "0.3.13"
ambassador = "0.4.1"
directories = "5.0"

rusqlite = { version = "0.32.1", features = ["functions"]}
Expand All @@ -49,4 +49,5 @@ image = { version = "0.25.2", default-features = false, features = ["png"] }
bitflags = "2.6.0"
libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
rust-embed = "8.5.0"
#zmq = "0.10"
zmq = "0.10"
zeroize = "1.8.1"
4 changes: 3 additions & 1 deletion dash_core_configs/mainnet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ rpcport=9998
rpcallowip=127.0.0.1/32
rpcuser=dashrpc
rpcpassword=password
server=1
server=1
zmqpubrawtxlocksig=tcp://0.0.0.0:23708
zmqpubrawchainlock=tcp://0.0.0.0:23708
4 changes: 3 additions & 1 deletion dash_core_configs/testnet.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ rpcport=19998
rpcallowip=127.0.0.1/32
rpcuser=dashrpc
rpcpassword=password
server=1
server=1
zmqpubrawtxlocksig=tcp://0.0.0.0:23709
zmqpubrawchainlock=tcp://0.0.0.0:23709
Binary file added icons/wallet.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
125 changes: 117 additions & 8 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@ use crate::app_dir::{
app_user_data_file_path, copy_env_file_if_not_exists,
create_app_user_data_directory_if_not_exists,
};
use crate::backend_task::core::CoreItem;
use crate::backend_task::{BackendTask, BackendTaskSuccessResult};
use crate::components::core_zmq_listener::{CoreZMQListener, ZMQMessage};
use crate::context::AppContext;
use crate::database::Database;
use crate::logging::initialize_logger;
use crate::platform::{BackendTask, BackendTaskSuccessResult};
use crate::ui::document_query_screen::DocumentQueryScreen;
use crate::ui::dpns_contested_names_screen::{DPNSContestedNamesScreen, DPNSSubscreen};
use crate::ui::identities::identities_screen::IdentitiesScreen;
use crate::ui::network_chooser_screen::NetworkChooserScreen;
use crate::ui::transition_visualizer_screen::TransitionVisualizerScreen;
use crate::ui::wallet::wallets_screen::WalletsBalancesScreen;
use crate::ui::withdraws_status_screen::WithdrawsStatusScreen;
use crate::ui::{MessageType, RootScreenType, Screen, ScreenLike, ScreenType};
use dash_sdk::dpp::dashcore::Network;
use derive_more::From;
use eframe::{egui, App};
use std::collections::BTreeMap;
use std::ops::BitOrAssign;
use std::sync::Arc;
use std::sync::{mpsc, Arc};
use std::time::Instant;
use std::vec;
use tokio::sync::mpsc;
use tokio::sync::mpsc as tokiompsc;

#[derive(Debug, From)]
pub enum TaskResult {
Expand All @@ -46,8 +49,11 @@ pub struct AppState {
pub chosen_network: Network,
pub mainnet_app_context: Arc<AppContext>,
pub testnet_app_context: Option<Arc<AppContext>>,
pub task_result_sender: mpsc::Sender<TaskResult>, // Channel sender for sending task results
pub task_result_receiver: mpsc::Receiver<TaskResult>, // Channel receiver for receiving task results
pub mainnet_core_zmq_listener: CoreZMQListener,
pub testnet_core_zmq_listener: CoreZMQListener,
pub core_message_receiver: mpsc::Receiver<(ZMQMessage, Network)>,
pub task_result_sender: tokiompsc::Sender<TaskResult>, // Channel sender for sending task results
pub task_result_receiver: tokiompsc::Receiver<TaskResult>, // Channel receiver for receiving task results
last_repaint: Instant, // Track the last time we requested a repaint
}

Expand Down Expand Up @@ -103,7 +109,8 @@ impl BitOrAssign for AppAction {
}
impl AppState {
pub fn new() -> Self {
create_app_user_data_directory_if_not_exists().expect("Failed to create app user_data directory");
create_app_user_data_directory_if_not_exists()
.expect("Failed to create app user_data directory");
copy_env_file_if_not_exists();
initialize_logger();
let db_file_path = app_user_data_file_path("data.db").expect("should create db file path");
Expand Down Expand Up @@ -140,6 +147,8 @@ impl AppState {
Network::Dash,
);

let mut wallets_balances_screen = WalletsBalancesScreen::new(&mainnet_app_context);

let mut selected_main_screen = RootScreenType::RootScreenIdentities;

let mut chosen_network = Network::Dash;
Expand All @@ -158,17 +167,36 @@ impl AppState {
DPNSContestedNamesScreen::new(&testnet_app_context, DPNSSubscreen::Owned);
transition_visualizer_screen = TransitionVisualizerScreen::new(testnet_app_context);
document_query_screen = DocumentQueryScreen::new(testnet_app_context);
wallets_balances_screen = WalletsBalancesScreen::new(testnet_app_context);
withdraws_status_screen = WithdrawsStatusScreen::new(testnet_app_context);
}
network_chooser_screen.current_network = chosen_network;
}

// // Create a channel with a buffer size of 32 (adjust as needed)
let (task_result_sender, task_result_receiver) = mpsc::channel(256);
let (task_result_sender, task_result_receiver) = tokiompsc::channel(256);

// Initialize the last repaint time to the current instant
let last_repaint = Instant::now();

// Create a channel for communication with the InstantSendListener
let (core_message_sender, core_message_receiver) = mpsc::channel();

// Pass the sender to the listener when creating it
let mainnet_core_zmq_listener = CoreZMQListener::spawn_listener(
Network::Dash,
"tcp://127.0.0.1:23708",
core_message_sender.clone(), // Clone the sender for each listener
)
.expect("Failed to create mainnet InstantSend listener");

let testnet_core_zmq_listener = CoreZMQListener::spawn_listener(
Network::Testnet,
"tcp://127.0.0.1:23709",
core_message_sender, // Use the original sender or create a new one if needed
)
.expect("Failed to create testnet InstantSend listener");

Self {
main_screens: [
(
Expand All @@ -187,6 +215,10 @@ impl AppState {
RootScreenType::RootScreenDPNSOwnedNames,
Screen::DPNSContestedNamesScreen(dpns_my_usernames_screen),
),
(
RootScreenType::RootScreenWalletsBalances,
Screen::WalletsBalancesScreen(wallets_balances_screen),
),
(
RootScreenType::RootScreenTransitionVisualizerScreen,
Screen::TransitionVisualizerScreen(transition_visualizer_screen),
Expand All @@ -210,6 +242,9 @@ impl AppState {
chosen_network,
mainnet_app_context,
testnet_app_context,
mainnet_core_zmq_listener,
testnet_core_zmq_listener,
core_message_receiver,
task_result_sender,
task_result_receiver,
last_repaint,
Expand Down Expand Up @@ -286,7 +321,40 @@ impl AppState {
}
}

impl AppState {}
impl AppState {
// /// This function continuously listens for asset locks and updates the wallets accordingly.
// fn start_listening_for_asset_locks(&mut self) {
// let instant_send_receiver = self.instant_send_receiver.clone(); // Clone the receiver
// let mainnet_app_context = self.mainnet_app_context.clone();
// let testnet_app_context = self.testnet_app_context.clone();
//
// // Spawn a new task to listen asynchronously for asset locks
// task::spawn_blocking(move || {
// while let Ok((tx, islock, network)) = instant_send_receiver.recv() {
// let app_context = match network {
// Network::Dash => &mainnet_app_context,
// Network::Testnet => {
// if let Some(context) = testnet_app_context.as_ref() {
// context
// } else {
// // Handle the case when testnet_app_context is None
// eprintln!("No testnet app context available for Testnet");
// continue; // Skip this iteration or handle as needed
// }
// }
// _ => continue,
// };
// // Store the asset lock transaction in the database
// if let Err(e) = app_context.store_asset_lock_in_db(&tx, islock) {
// eprintln!("Failed to store asset lock: {}", e);
// }
//
// // Sleep briefly to avoid busy-waiting
// std::thread::sleep(Duration::from_millis(50));
// }
// });
// }
}

impl App for AppState {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
Expand Down Expand Up @@ -325,6 +393,47 @@ impl App for AppState {
}
}

// **Poll the instant_send_receiver for any new InstantSend messages**
while let Ok((message, network)) = self.core_message_receiver.try_recv() {
let app_context = match network {
Network::Dash => &self.mainnet_app_context,
Network::Testnet => {
if let Some(context) = self.testnet_app_context.as_ref() {
context
} else {
// Handle the case when testnet_app_context is None
eprintln!("No testnet app context available for Testnet");
continue; // Skip this iteration or handle as needed
}
}
_ => continue,
};
match message {
ZMQMessage::ISLockedTransaction(tx, is_lock) => {
// Store the asset lock transaction in the database
match app_context.received_transaction_finality(&tx, Some(is_lock), None) {
Ok(utxos) => {
let core_item =
CoreItem::ReceivedAvailableUTXOTransaction(tx.clone(), utxos);
self.visible_screen_mut()
.display_task_result(core_item.into());
}
Err(e) => {
eprintln!("Failed to store asset lock: {}", e);
}
}
}
ZMQMessage::ChainLockedLockedTransaction(tx, height) => {
if let Err(e) =
app_context.received_transaction_finality(&tx, None, Some(height))
{
eprintln!("Failed to store asset lock: {}", e);
}
}
ZMQMessage::ChainLockedBlock(_) => {}
}
}

// Use a timer to repaint the UI every 0.05 seconds
ctx.request_repaint_after(std::time::Duration::from_millis(50));

Expand Down
25 changes: 11 additions & 14 deletions src/app_dir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ const ORGANIZATION: &str = "";
const APPLICATION: &str = "DashEvoTool";

pub fn app_user_data_dir_path() -> Result<PathBuf, std::io::Error> {
let proj_dirs = ProjectDirs::from(QUALIFIER, ORGANIZATION, APPLICATION)
.ok_or_else(|| std::io::Error::new(
let proj_dirs = ProjectDirs::from(QUALIFIER, ORGANIZATION, APPLICATION).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::NotFound,
"Failed to determine project directories",
))?;
)
})?;
Ok(proj_dirs.config_dir().to_path_buf())
}
pub fn create_app_user_data_directory_if_not_exists() -> Result<(), std::io::Error> {
Expand Down Expand Up @@ -41,23 +42,19 @@ pub fn app_user_data_file_path(filename: &str) -> Result<PathBuf, std::io::Error
}

pub fn copy_env_file_if_not_exists() {
let app_data_dir = app_user_data_dir_path().expect("Failed to determine application data directory");
let app_data_dir =
app_user_data_dir_path().expect("Failed to determine application data directory");
let env_file_in_app_dir = app_data_dir.join(".env".to_string());
if env_file_in_app_dir.exists() && env_file_in_app_dir.is_file() {
} else {
let env_example_file_in_exe_dir = PathBuf::from(".env.example");
if env_example_file_in_exe_dir.exists() && env_example_file_in_exe_dir.is_file() {
fs::copy(
&env_example_file_in_exe_dir,
env_file_in_app_dir,
).expect("Failed to copy main net env file");
}
else {
fs::copy(&env_example_file_in_exe_dir, env_file_in_app_dir)
.expect("Failed to copy main net env file");
} else {
let env_file_in_exe_dir = PathBuf::from(".env");
fs::copy(
&env_file_in_exe_dir,
env_file_in_app_dir,
).expect("Failed to copy main net env file");
fs::copy(&env_file_in_exe_dir, env_file_in_app_dir)
.expect("Failed to copy main net env file");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ mod query_ending_times;
mod vote_on_dpns_name;

use crate::app::TaskResult;
use crate::backend_task::BackendTaskSuccessResult;
use crate::context::AppContext;
use crate::model::qualified_identity::QualifiedIdentity;
use crate::platform::BackendTaskSuccessResult;
use dash_sdk::dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice;
use dash_sdk::Sdk;
use std::sync::Arc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl AppContext {
&self,
name: &String,
sdk: Sdk,
sender: mpsc::Sender<TaskResult>,
_sender: mpsc::Sender<TaskResult>,
) -> Result<(), String> {
let data_contract = self.dpns_contract.as_ref();
let document_type = data_contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ impl AppContext {
pub(super) async fn query_dpns_ending_times(
self: &Arc<Self>,
sdk: Sdk,
sender: mpsc::Sender<TaskResult>,
_sender: mpsc::Sender<TaskResult>,
) -> Result<(), String> {
let now: DateTime<Utc> = Utc::now();
let start_time_dt = now - Duration::weeks(2);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::app::TaskResult;
use crate::backend_task::BackendTaskSuccessResult;
use crate::context::AppContext;
use crate::model::qualified_identity::QualifiedIdentity;
use crate::platform::BackendTaskSuccessResult;
use dash_sdk::dpp::data_contract::accessors::v0::DataContractV0Getters;
use dash_sdk::dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
use dash_sdk::dpp::identity::accessors::IdentityGettersV0;
Expand Down
File renamed without changes.
48 changes: 48 additions & 0 deletions src/backend_task/core/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
mod refresh_wallet_info;

use crate::backend_task::BackendTaskSuccessResult;
use crate::context::AppContext;
use crate::model::wallet::Wallet;
use dash_sdk::dashcore_rpc::RpcApi;
use dash_sdk::dpp::dashcore::{ChainLock, Network, OutPoint, Transaction};
use dash_sdk::platform::proto::Proof;
use std::sync::{Arc, RwLock};

#[derive(Debug, Clone)]
pub(crate) enum CoreTask {
GetBestChainLock,
RefreshWalletInfo(Arc<RwLock<Wallet>>),
}
impl PartialEq for CoreTask {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(CoreTask::GetBestChainLock, CoreTask::GetBestChainLock) => true,
(CoreTask::RefreshWalletInfo(_), CoreTask::RefreshWalletInfo(_)) => true,
_ => false,
}
}
}

#[derive(Debug, Clone, PartialEq)]
pub(crate) enum CoreItem {
ReceivedAvailableUTXOTransaction(Transaction, Vec<OutPoint>),
ChainLock(ChainLock, Network),
}

impl AppContext {
pub async fn run_core_task(&self, task: CoreTask) -> Result<BackendTaskSuccessResult, String> {
match task {
CoreTask::GetBestChainLock => self
.core_client
.get_best_chain_lock()
.map(|chain_lock| {
BackendTaskSuccessResult::CoreItem(CoreItem::ChainLock(
chain_lock,
self.network,
))
})
.map_err(|e| e.to_string()),
CoreTask::RefreshWalletInfo(wallet) => self.refresh_wallet_info(wallet),
}
}
}
Loading