drk.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi::{
  19. system::{Publisher, PublisherPtr, StoppableTask, sleep},
  20. tx::Transaction,
  21. util::parse::encode_base10,
  22. };
  23. use darkfi_money_contract::model::TokenId;
  24. use darkfi_serial::{serialize, Decodable, Encodable};
  25. use darkfi_sdk::crypto::{keypair::{Address, Network, PublicKey, StandardAddress}};
  26. use drk::{Drk, money::BALANCE_BASE10_DECIMALS, rpc::subscribe_blocks};
  27. use smol::lock::RwLock;
  28. use smol::channel::unbounded;
  29. use std::{
  30. io::Cursor,
  31. sync::{Arc, OnceLock, Weak},
  32. };
  33. use url::Url;
  34. use crate::{
  35. error::{Error, Result},
  36. prop::BatchGuardPtr,
  37. scene::{
  38. MethodCallSub, Pimpl, SceneNode, SceneNodePtr, SceneNodeType, SceneNodeWeak,
  39. },
  40. ExecutorPtr,
  41. };
  42. const DARKFID_RETRY_TIME: u64 = 20;
  43. #[cfg(target_os = "android")]
  44. mod paths {
  45. use crate::android::{get_appdata_path, get_external_storage_path};
  46. use std::path::PathBuf;
  47. pub fn get_cache_path() -> PathBuf {
  48. get_external_storage_path().join("drk/cache")
  49. }
  50. pub fn get_wallet_path() -> PathBuf {
  51. get_external_storage_path().join("drk/wallet.db")
  52. }
  53. pub fn get_use_tor_filename() -> PathBuf {
  54. get_external_storage_path().join("use_tor.txt")
  55. }
  56. }
  57. #[cfg(not(target_os = "android"))]
  58. mod paths {
  59. use std::path::PathBuf;
  60. pub fn get_cache_path() -> PathBuf {
  61. dirs::data_local_dir().unwrap().join("darkfi/app/drk/cache")
  62. }
  63. pub fn get_wallet_path() -> PathBuf {
  64. dirs::data_local_dir().unwrap().join("darkfi/app/drk/wallet.db")
  65. }
  66. pub fn get_use_tor_filename() -> PathBuf {
  67. dirs::data_local_dir().unwrap().join("darkfi/app/drk/use_tor.txt")
  68. }
  69. }
  70. use paths::*;
  71. macro_rules! t { ($($arg:tt)*) => { trace!(target: "plugin::drk", $($arg)*); } }
  72. macro_rules! d { ($($arg:tt)*) => { debug!(target: "plugin::drk", $($arg)*); } }
  73. macro_rules! i { ($($arg:tt)*) => { info!(target: "plugin::drk", $($arg)*); } }
  74. macro_rules! e { ($($arg:tt)*) => { error!(target: "plugin::drk", $($arg)*); } }
  75. #[derive(Debug, Clone)]
  76. enum TxStatus {
  77. Building,
  78. Broadcasting,
  79. Confirming,
  80. Confirmed,
  81. Error(String),
  82. }
  83. impl TxStatus {
  84. fn text(&self) -> String {
  85. match self {
  86. TxStatus::Building => "Building transaction...".to_string(),
  87. TxStatus::Broadcasting => "Broadcasting transaction...".to_string(),
  88. TxStatus::Confirming => "Confirming transaction...".to_string(),
  89. TxStatus::Confirmed => "Transaction confirmed".to_string(),
  90. TxStatus::Error(ref err) => format!("Error sending transaction: {err}"),
  91. }
  92. }
  93. }
  94. #[derive(Debug, Clone)]
  95. struct TxState {
  96. id: Option<String>,
  97. status: TxStatus,
  98. amount: Option<String>,
  99. token_symbol: Option<String>,
  100. recipient: Option<Address>,
  101. }
  102. pub type DrkPluginPtr = Arc<DrkPlugin>;
  103. #[derive(Debug, Clone)]
  104. struct BuildTxRequest {
  105. amount: String,
  106. token_id: TokenId,
  107. recipient: PublicKey,
  108. }
  109. pub struct DrkPlugin {
  110. node: SceneNodeWeak,
  111. sg_root: SceneNodePtr,
  112. tasks: OnceLock<Vec<smol::Task<()>>>,
  113. scan_progress_pub: PublisherPtr<(u32, u32)>,
  114. drk: Arc<RwLock<Drk>>,
  115. build_tx_channel: smol::channel::Sender<BuildTxRequest>,
  116. }
  117. impl DrkPlugin {
  118. pub async fn new<'a>(
  119. node: SceneNodeWeak,
  120. sg_root: SceneNodePtr,
  121. ex: ExecutorPtr,
  122. ) -> Result<(Pimpl, Arc<smol::LocalExecutor<'a>>)> {
  123. let node_ref = &node.upgrade().unwrap();
  124. let setting_root = Arc::new(SceneNode::new("setting", SceneNodeType::SettingRoot));
  125. node_ref.clone().link(setting_root.clone());
  126. let endpoint = Url::parse("tcp://127.0.0.1:18345").unwrap();
  127. let drk = match Drk::new(Network::Testnet, get_cache_path().to_string_lossy().to_string(), get_wallet_path().to_string_lossy().to_string(), "changeme".to_string(), Some(endpoint), &ex, false).await {
  128. Ok(wallet) => wallet,
  129. Err(e) => {
  130. eprintln!("Error initializing wallet: {e}");
  131. return Err(Error::ServiceFailed); // TODO: make a better error
  132. }
  133. };
  134. if let Err(e) = drk.initialize_wallet().await {
  135. e!("Error initializing wallet: {e}");
  136. }
  137. let mut output = vec![];
  138. if let Err(e) = drk.initialize_money(&mut output).await {
  139. e!("Failed to initialize Money: {e}");
  140. }
  141. if let Err(e) = drk.initialize_dao().await {
  142. e!("Failed to initialize DAO: {e}");
  143. }
  144. if let Err(e) = drk.initialize_deployooor() {
  145. e!("Failed to initialize Deployooor: {e}");
  146. }
  147. // Generate a default address if needed
  148. match drk.default_address().await {
  149. Ok(_) => {
  150. i!("Default address already exists");
  151. }
  152. Err(e) => {
  153. i!("No default address found ({}), generating one...", e);
  154. if let Err(e) = drk.money_keygen(&mut output).await {
  155. e!("Failed to generate keypair: {e}");
  156. } else {
  157. i!("Generated default address");
  158. match drk.addresses().await {
  159. Ok(addrs) => {
  160. if let Some((key_id, _, _, _)) = addrs.last() {
  161. i!("Setting address with key_id {} as default", key_id);
  162. if let Err(e) = drk.set_default_address(*key_id as usize) {
  163. e!("Failed to set default address: {e}");
  164. }
  165. }
  166. }
  167. Err(e) => {
  168. e!("Failed to get addresses: {e}");
  169. }
  170. }
  171. }
  172. }
  173. }
  174. // Create channel for build_tx requests
  175. let (build_tx_tx, build_tx_rx) = smol::channel::unbounded();
  176. let self_ = Arc::new(Self {
  177. node: node.clone(),
  178. sg_root,
  179. tasks: OnceLock::new(),
  180. drk: drk.into_ptr(),
  181. build_tx_channel: build_tx_tx,
  182. scan_progress_pub: Publisher::new(),
  183. });
  184. let local_ex = smol::LocalExecutor::new();
  185. let local_ex = Arc::new(local_ex);
  186. // Start background task to process build_tx requests from channel
  187. let me3 = Arc::downgrade(&self_);
  188. let build_tx_processor = local_ex.spawn(async move {
  189. while let Ok(request) = build_tx_rx.recv().await {
  190. if let Some(self_) = me3.upgrade() {
  191. match self_.build_tx_request(request).await {
  192. Ok((tx, token_symbol, recipient, amount)) => {
  193. self_.emit_tx_built(amount, token_symbol, recipient, tx).await;
  194. }
  195. Err(e) => {
  196. e!("Failed to build transaction: {e}");
  197. self_.emit_tx_built_error(e.to_string()).await;
  198. }
  199. }
  200. }
  201. }
  202. });
  203. let node_ref = node.upgrade().unwrap();
  204. let me2 = Arc::downgrade(&self_);
  205. let method_sub = node_ref.subscribe_method_call("get_default_address").unwrap();
  206. let get_address_task = local_ex.spawn(async move {
  207. while Self::process_get_default_address(&me2, &method_sub).await {}
  208. });
  209. let node_ref = node.upgrade().unwrap();
  210. let me2 = Arc::downgrade(&self_);
  211. let method_sub_balances = node_ref.subscribe_method_call("get_balances").unwrap();
  212. let get_balances_task = local_ex.spawn(async move {
  213. while Self::process_get_balances(&me2, &method_sub_balances).await {}
  214. });
  215. let node_ref = node.upgrade().unwrap();
  216. let me2 = Arc::downgrade(&self_);
  217. let method_sub_tx_status = node_ref.subscribe_method_call("get_tx_status").unwrap();
  218. let get_tx_status_task = local_ex.spawn(async move {
  219. while Self::process_get_tx_status(&me2, &method_sub_tx_status).await {}
  220. });
  221. let node_ref = node.upgrade().unwrap();
  222. let me2 = Arc::downgrade(&self_);
  223. let method_sub_build_tx = node_ref.subscribe_method_call("build_tx").unwrap();
  224. let build_tx_task = local_ex.spawn(async move {
  225. while Self::process_build_tx(&me2, &method_sub_build_tx).await {}
  226. });
  227. let node_ref = node.upgrade().unwrap();
  228. let me2 = Arc::downgrade(&self_);
  229. let method_sub_broadcast_tx = node_ref.subscribe_method_call("broadcast_tx").unwrap();
  230. let broadcast_tx_task = local_ex.spawn(async move {
  231. while Self::process_broadcast_tx(&me2, &method_sub_broadcast_tx).await {}
  232. });
  233. let tasks = vec![get_address_task, get_balances_task, get_tx_status_task, build_tx_task, broadcast_tx_task, build_tx_processor];
  234. self_.clone().start(ex.clone(), local_ex.clone(), tasks).await;
  235. Ok((Pimpl::Drk(self_), local_ex))
  236. }
  237. async fn apply_settings(_self: Arc<Self>, _batch: BatchGuardPtr) {
  238. // TODO
  239. }
  240. pub async fn get_default_address(&self) -> Result<String> {
  241. let drk = self.drk.read().await;
  242. let pubkey = drk.default_address().await.map_err(|e| {
  243. e!("Failed to get default address: {e}");
  244. Error::ServiceFailed
  245. })?;
  246. let network = drk.network;
  247. let address: darkfi_sdk::crypto::keypair::Address =
  248. StandardAddress::from_public(network, pubkey).into();
  249. Ok(address.to_string())
  250. }
  251. pub async fn get_balances(&self) -> Result<Vec<(String, TokenId, u64)>> {
  252. let drk = self.drk.read().await;
  253. let balances = drk.money_balance().await.map_err(|e| {
  254. e!("Failed to get money balance: {e}");
  255. Error::ServiceFailed
  256. })?;
  257. let aliases = drk.get_aliases_mapped_by_token().await.map_err(|e| {
  258. e!("Failed to get aliases: {e}");
  259. Error::ServiceFailed
  260. })?;
  261. let mut result: Vec<(String, TokenId, u64)> = Vec::new();
  262. for (token_id_str, balance) in balances {
  263. let encoded = encode_base10(balance, BALANCE_BASE10_DECIMALS);
  264. let alias = aliases.get(&token_id_str).cloned().unwrap_or_else(|| "UNKN".to_string());
  265. let token_id = token_id_str.parse::<TokenId>().unwrap();
  266. result.push((alias, token_id, balance));
  267. }
  268. // Sort by balance
  269. result.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap_or(std::cmp::Ordering::Equal));
  270. Ok(result)
  271. }
  272. /// Emit balances_updated signal
  273. pub async fn emit_balances_updated(&self) {
  274. if let Some(node) = self.node.upgrade() {
  275. let _ = node.trigger("balances_updated", vec![]).await;
  276. }
  277. }
  278. /// Emit tx_updated signal
  279. pub async fn emit_tx_updated(&self, state: &TxState) {
  280. if let Some(node) = self.node.upgrade() {
  281. let mut data = vec![];
  282. state.id.clone().encode(&mut data).unwrap();
  283. Some(state.status.text()).encode(&mut data).unwrap();
  284. state.amount.encode(&mut data).unwrap();
  285. state.token_symbol.clone().encode(&mut data).unwrap();
  286. state.recipient.map(|r| r.to_string()).encode(&mut data).unwrap();
  287. let _ = node.trigger("tx_updated", data).await;
  288. }
  289. }
  290. pub async fn emit_tx_status_updated(&self, status: &TxStatus) {
  291. if let Some(node) = self.node.upgrade() {
  292. let mut data = vec![];
  293. None::<String>.encode(&mut data).unwrap();
  294. Some(status.text()).encode(&mut data).unwrap();
  295. None::<String>.encode(&mut data).unwrap();
  296. None::<String>.encode(&mut data).unwrap();
  297. None::<String>.encode(&mut data).unwrap();
  298. let _ = node.trigger("tx_updated", data).await;
  299. }
  300. }
  301. /// Emit tx_built signal when transaction is built
  302. pub async fn emit_tx_built(&self, amount: String, token_symbol: String, recipient: Address, tx: Transaction) {
  303. if let Some(node) = self.node.upgrade() {
  304. let mut data = vec![];
  305. amount.encode(&mut data).unwrap();
  306. token_symbol.encode(&mut data).unwrap();
  307. recipient.to_string().encode(&mut data).unwrap();
  308. tx.encode(&mut data).unwrap();
  309. let _ = node.trigger("tx_built", data).await;
  310. }
  311. }
  312. /// Emit tx_built_error signal when transaction building fails
  313. pub async fn emit_tx_built_error(&self, error: String) {
  314. if let Some(node) = self.node.upgrade() {
  315. let mut data = vec![];
  316. error.encode(&mut data).unwrap();
  317. let _ = node.trigger("tx_built_error", data).await;
  318. }
  319. }
  320. async fn process_get_default_address(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  321. let Ok(method_call) = sub.receive().await else {
  322. d!("get_default_address method closed");
  323. return false
  324. };
  325. t!("method called: get_default_address()");
  326. let Some(self_) = me.upgrade() else {
  327. e!("drk plugin destroyed before get_default_address task was stopped!");
  328. if let Some(send_res) = method_call.send_res {
  329. let _ = send_res.send(vec![]).await;
  330. }
  331. return false
  332. };
  333. let address = match self_.get_default_address().await {
  334. Ok(addr) => addr,
  335. Err(e) => {
  336. e!("Failed to get default address: {e}");
  337. if let Some(send_res) = method_call.send_res {
  338. let _ = send_res.send(vec![]).await;
  339. }
  340. return true
  341. }
  342. };
  343. i!("Got default address: {address}");
  344. if let Some(send_res) = method_call.send_res {
  345. let mut cur = Cursor::new(vec![]);
  346. if address.encode(&mut cur).is_ok() {
  347. let _ = send_res.send(cur.into_inner()).await;
  348. } else {
  349. e!("Failed to encode default address");
  350. let _ = send_res.send(vec![]).await;
  351. }
  352. } else {
  353. e!("No send_res channel available");
  354. }
  355. true
  356. }
  357. async fn process_get_balances(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  358. let Ok(method_call) = sub.receive().await else {
  359. d!("get_balances method closed");
  360. return false
  361. };
  362. t!("method called: get_balances()");
  363. let Some(self_) = me.upgrade() else {
  364. e!("drk plugin destroyed before get_balances task was stopped!");
  365. if let Some(send_res) = method_call.send_res {
  366. let _ = send_res.send(vec![]).await;
  367. }
  368. return false
  369. };
  370. let balances = match self_.get_balances().await {
  371. Ok(b) => b,
  372. Err(e) => {
  373. e!("Failed to get balances: {e}");
  374. if let Some(send_res) = method_call.send_res {
  375. let _ = send_res.send(vec![]).await;
  376. }
  377. return true
  378. }
  379. };
  380. if let Some(send_res) = method_call.send_res {
  381. let mut cur = Cursor::new(vec![]);
  382. if balances.encode(&mut cur).is_ok() {
  383. let _ = send_res.send(cur.into_inner()).await;
  384. } else {
  385. e!("Failed to encode balances");
  386. let _ = send_res.send(vec![]).await;
  387. }
  388. } else {
  389. e!("No send_res channel available");
  390. }
  391. true
  392. }
  393. async fn process_get_tx_status(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  394. let Ok(method_call) = sub.receive().await else {
  395. d!("get_tx_history method closed");
  396. return false
  397. };
  398. t!("method called: get_tx_status()");
  399. fn decode_data(data: &[u8]) -> std::io::Result<String> {
  400. let mut cur = Cursor::new(&data);
  401. let tx_id = String::decode(&mut cur)?;
  402. Ok(tx_id)
  403. }
  404. let Ok(tx_id) = decode_data(&method_call.data) else {
  405. d!("get_tx_status() method invalid arg data");
  406. return true
  407. };
  408. let Some(self_) = me.upgrade() else {
  409. e!("drk plugin destroyed before get_tx_status task was stopped!");
  410. if let Some(send_res) = method_call.send_res {
  411. let _ = send_res.send(vec![]).await;
  412. }
  413. return false
  414. };
  415. let drk = self_.drk.read().await;
  416. let Ok((_, status, _block_height, _tx)) = drk.get_tx_history_record(&tx_id).await else {
  417. d!("get_tx_history() method failed to get tx history record");
  418. return true
  419. };
  420. if let Some(send_res) = method_call.send_res {
  421. let mut cur = Cursor::new(vec![]);
  422. let status = match status.as_str() {
  423. "Broadcasted" => TxStatus::Confirming,
  424. "Confirmed" => TxStatus::Confirmed,
  425. _ => TxStatus::Error("unknown status".to_string()),
  426. };
  427. if status.text().encode(&mut cur).is_ok() {
  428. let _ = send_res.send(cur.into_inner()).await;
  429. } else {
  430. e!("Failed to encode balances");
  431. let _ = send_res.send(vec![]).await;
  432. }
  433. } else {
  434. e!("No send_res channel available");
  435. }
  436. true
  437. }
  438. /// Build a transaction without broadcasting it
  439. pub async fn build_tx(&self, amount: &str, token_id: TokenId, recipient: PublicKey) -> Result<Transaction> {
  440. let drk = self.drk.read().await;
  441. drk.transfer(amount, token_id, recipient, None, None, false).await.map_err(|e| {
  442. e!("Failed to build transaction: {e}");
  443. Error::ServiceFailed
  444. })
  445. }
  446. /// Build a transaction from a BuildTxRequest (called by background task)
  447. async fn build_tx_request(&self, request: BuildTxRequest) -> Result<(Transaction, String, Address, String)> {
  448. let drk = self.drk.read().await;
  449. let aliases = drk.get_aliases_mapped_by_token().await.unwrap_or_default();
  450. let token_symbol = aliases.get(&request.token_id.to_string()).unwrap_or(&"UNKN".to_string()).to_string();
  451. let recipient: Address = StandardAddress::from_public(drk.network, request.recipient).into();
  452. let tx = self.build_tx(&request.amount, request.token_id, request.recipient).await?;
  453. Ok((tx, token_symbol, recipient, request.amount))
  454. }
  455. async fn process_build_tx(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  456. let Ok(method_call) = sub.receive().await else {
  457. d!("build_tx method closed");
  458. return false
  459. };
  460. t!("method called: build_tx()");
  461. // Send empty response immediately to unblock the caller
  462. if let Some(send_res) = method_call.send_res {
  463. let _ = send_res.send(vec![]).await;
  464. }
  465. fn decode_data(data: &[u8]) -> std::io::Result<(String, TokenId, PublicKey)> {
  466. let mut cur = Cursor::new(&data);
  467. let amount = String::decode(&mut cur)?;
  468. let token_id = TokenId::decode(&mut cur)?;
  469. let recipient = PublicKey::decode(&mut cur)?;
  470. Ok((amount, token_id, recipient))
  471. }
  472. let Ok((amount, token_id, recipient)) = decode_data(&method_call.data) else {
  473. d!("build_tx() method invalid arg data");
  474. return true
  475. };
  476. let Some(self_) = me.upgrade() else {
  477. e!("drk plugin destroyed before build_tx task was stopped!");
  478. return false
  479. };
  480. // Send request to channel for background processing
  481. let request = BuildTxRequest { amount, token_id, recipient };
  482. let _ = self_.build_tx_channel.send(request).await;
  483. true
  484. }
  485. /// Broadcast a transaction
  486. pub async fn broadcast_tx(&self, tx: Transaction) -> Result<String> {
  487. let drk = self.drk.read().await;
  488. let tx_id = drk.broadcast_tx(&tx, &mut vec![]).await.map_err(|e| {
  489. e!("Failed to broadcast transaction: {e}");
  490. Error::ServiceFailed
  491. })?;
  492. Ok(tx_id)
  493. }
  494. async fn process_broadcast_tx(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  495. let Ok(method_call) = sub.receive().await else {
  496. d!("broadcast_tx method closed");
  497. return false
  498. };
  499. t!("method called: broadcast_tx()");
  500. let Some(send_res) = method_call.send_res else {
  501. return true
  502. };
  503. // Send empty response immediately to unblock the caller
  504. let _ = send_res.send(vec![]).await;
  505. let Some(self_) = me.upgrade() else {
  506. e!("drk plugin destroyed before broadcast_tx task was stopped!");
  507. return false
  508. };
  509. let Ok(tx) = Transaction::decode(&mut Cursor::new(&method_call.data)) else {
  510. d!("broadcast_tx() method invalid arg data");
  511. return true
  512. };
  513. let drk = self_.drk.read().await;
  514. if let Err(e) = drk.mark_tx_spend(&tx, &mut vec![]).await {
  515. e!("Failed to mark transaction coins as spent: {e}");
  516. self_.emit_tx_status_updated(&TxStatus::Error("failed to mark coins as spent".to_string())).await;
  517. return true
  518. };
  519. let tx_id = match drk.broadcast_tx(&tx, &mut vec![]).await {
  520. Ok(t) => t,
  521. Err(e) => {
  522. e!("Failed to broadcast transaction: {e}");
  523. self_.emit_tx_status_updated(&TxStatus::Error("failed to broadcast".to_string())).await;
  524. return true
  525. }
  526. };
  527. drop(drk);
  528. let state = TxState {
  529. id: Some(tx_id),
  530. status: TxStatus::Confirming,
  531. amount: None,
  532. token_symbol: None,
  533. recipient: None,
  534. };
  535. self_.emit_tx_updated(&state).await;
  536. true
  537. }
  538. async fn start(self: Arc<Self>, ex: ExecutorPtr, local_ex: Arc<smol::LocalExecutor<'_>>, tasks: Vec<smol::Task<()>>) {
  539. let endpoint = Url::parse("tcp://127.0.0.1:18345").unwrap();
  540. let self2 = self.clone();
  541. let drk = self.drk.clone();
  542. let (shell_sender, shell_receiver) = unbounded();
  543. let ex_ = ex.clone();
  544. let progress_sub = self.scan_progress_pub.clone().subscribe().await;
  545. let scan_progress_task = local_ex.spawn(async move {
  546. let mut first_height = None;
  547. loop {
  548. let (height, final_height) = progress_sub.receive().await;
  549. if first_height.is_none() {
  550. first_height = Some(height);
  551. }
  552. let progress: f64 = match final_height-first_height.unwrap() {
  553. 0 => 0.,
  554. _ => (height-first_height.unwrap()) as f64 / (final_height-first_height.unwrap()) as f64,
  555. };
  556. let status: u8 = if progress > 0.5 {
  557. 2
  558. } else {
  559. 1
  560. };
  561. if let Some(node) = self2.node.upgrade() {
  562. let _ = node.trigger("connect", serialize(&status)).await;
  563. }
  564. }
  565. });
  566. let self2 = self.clone();
  567. // Task that handles the RPC subscription with retry logic
  568. let subscribe_task = local_ex.spawn(async move {
  569. loop {
  570. i!("Attempting to connect to darkfid daemon at {}", endpoint);
  571. let subscribe_rpc_task = StoppableTask::new();
  572. let shell_sender = shell_sender.clone();
  573. let drk = drk.clone();
  574. let endpoint = endpoint.clone();
  575. let ex = ex_.clone();
  576. let progress_pub = self2.scan_progress_pub.clone();
  577. let _ = self2.node.upgrade().unwrap().trigger("connect", serialize(&0u8)).await;
  578. if let Err(e) = drk.read().await.scan_blocks(&mut vec![], Some(&shell_sender), &false, Some(progress_pub)).await {
  579. e!("Failed during drk scanning: {e}");
  580. let _ = self2.node.upgrade().unwrap().trigger("connect", serialize(&0u8)).await;
  581. // Wait before retrying
  582. i!("Retrying connection to darkfid in {} seconds...", DARKFID_RETRY_TIME);
  583. sleep(DARKFID_RETRY_TIME).await;
  584. continue
  585. }
  586. let _ = self2.node.upgrade().unwrap().trigger("connect", serialize(&3u8)).await;
  587. match subscribe_blocks(&drk, subscribe_rpc_task, shell_sender.clone(), endpoint, &ex).await {
  588. Ok(()) => {
  589. i!("darkfid subscription closed normally (detached task stopped)");
  590. }
  591. Err(e) => {
  592. e!("darkfid connection failed: {e}");
  593. }
  594. }
  595. let _ = self2.node.upgrade().unwrap().trigger("connect", serialize(&0u8)).await;
  596. // Wait before retrying
  597. i!("Retrying connection to darkfid in {} seconds...", DARKFID_RETRY_TIME);
  598. sleep(DARKFID_RETRY_TIME).await;
  599. }
  600. });
  601. let self2 = self.clone();
  602. let subscribe_recv_task = local_ex.spawn(async move {
  603. loop {
  604. let recv = shell_receiver.recv().await;
  605. if let Ok(lines) = recv {
  606. self2.emit_balances_updated().await;
  607. for line in lines.iter() {
  608. i!(line);
  609. }
  610. }
  611. }
  612. });
  613. let mut all_tasks = vec![scan_progress_task, subscribe_task, subscribe_recv_task];
  614. all_tasks.extend(tasks);
  615. self.tasks.set(all_tasks).unwrap();
  616. }
  617. }