drk.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  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::{sleep, Publisher, PublisherPtr, StoppableTask},
  20. tx::Transaction,
  21. Result as DarkFiResult,
  22. };
  23. use darkfi_money_contract::model::TokenId;
  24. use darkfi_sdk::crypto::keypair::{Address, Network, PublicKey, StandardAddress};
  25. use darkfi_serial::{serialize, Decodable, Encodable};
  26. use drk::{rpc::subscribe_blocks, Drk};
  27. use parking_lot::Mutex as SyncMutex;
  28. use smol::{channel::unbounded, lock::RwLock};
  29. use std::{
  30. io::Cursor,
  31. sync::{Arc, OnceLock, Weak},
  32. };
  33. use url::Url;
  34. use crate::{
  35. error::{Error, Result},
  36. scene::{MethodCallSub, Pimpl, SceneNodePtr, SceneNodeWeak},
  37. ExecutorPtr,
  38. };
  39. // TODO: should be configurable at runtime
  40. //const DARKFID_ENDPOINT: &str = "tcp://127.0.0.1:18345";
  41. const DARKFID_ENDPOINT: &str = "tcp+tls://node0.testnet.dark.fi:18345";
  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. Confirming,
  78. Confirmed,
  79. Error(String),
  80. }
  81. impl TxStatus {
  82. fn text(&self) -> String {
  83. match self {
  84. TxStatus::Confirming => "Confirming transaction...".to_string(),
  85. TxStatus::Confirmed => "Transaction confirmed".to_string(),
  86. TxStatus::Error(ref err) => format!("Error sending transaction: {err}"),
  87. }
  88. }
  89. }
  90. #[derive(Debug, Clone)]
  91. struct TxState {
  92. id: Option<String>,
  93. status: TxStatus,
  94. amount: Option<String>,
  95. token_symbol: Option<String>,
  96. recipient: Option<Address>,
  97. }
  98. pub type DrkPluginPtr = Arc<DrkPlugin>;
  99. #[derive(Debug, Clone)]
  100. struct BuildTxRequest {
  101. amount: String,
  102. token_id: TokenId,
  103. recipient: PublicKey,
  104. }
  105. pub struct DrkPlugin {
  106. node: SceneNodeWeak,
  107. sg_root: SceneNodePtr,
  108. tasks: OnceLock<Vec<smol::Task<()>>>,
  109. scan_progress_pub: PublisherPtr<(u32, u32)>,
  110. drk: Arc<RwLock<Drk>>,
  111. build_tx_channel: smol::channel::Sender<BuildTxRequest>,
  112. last_balances: SyncMutex<Option<Vec<(String, TokenId, u64)>>>,
  113. }
  114. impl DrkPlugin {
  115. pub async fn new(node: SceneNodeWeak, sg_root: SceneNodePtr, ex: ExecutorPtr) -> Result<Pimpl> {
  116. let node_ref = node.upgrade().unwrap();
  117. let endpoint = Url::parse(DARKFID_ENDPOINT).unwrap();
  118. let drk = match Drk::new(
  119. Network::Testnet,
  120. get_cache_path().to_string_lossy().to_string(),
  121. get_wallet_path().to_string_lossy().to_string(),
  122. "changeme".to_string(),
  123. Some(endpoint),
  124. &ex,
  125. false,
  126. )
  127. .await
  128. {
  129. Ok(wallet) => wallet,
  130. Err(e) => {
  131. eprintln!("Error initializing wallet: {e}");
  132. return Err(Error::ServiceFailed); // TODO: make a better error
  133. }
  134. };
  135. if let Err(e) = drk.initialize_wallet().await {
  136. e!("Error initializing wallet: {e}");
  137. }
  138. let mut output = vec![];
  139. if let Err(e) = drk.initialize_money(&mut output).await {
  140. e!("Failed to initialize Money: {e}");
  141. }
  142. if let Err(e) = drk.initialize_dao().await {
  143. e!("Failed to initialize DAO: {e}");
  144. }
  145. if let Err(e) = drk.initialize_deployooor().await {
  146. e!("Failed to initialize Deployooor: {e}");
  147. }
  148. // Generate a default address if needed
  149. match drk.default_address().await {
  150. Ok(_) => {
  151. i!("Default address already exists");
  152. }
  153. Err(e) => {
  154. i!("No default address found ({}), generating one...", e);
  155. if let Err(e) = drk.money_keygen(&mut output).await {
  156. e!("Failed to generate keypair: {e}");
  157. } else {
  158. i!("Generated default address");
  159. match drk.addresses().await {
  160. Ok(addrs) => {
  161. if let Some((key_id, _, _, _)) = addrs.last() {
  162. i!("Setting address with key_id {} as default", key_id);
  163. if let Err(e) = drk.set_default_address(*key_id as u16).await {
  164. e!("Failed to set default address: {e}");
  165. }
  166. }
  167. }
  168. Err(e) => {
  169. e!("Failed to get addresses: {e}");
  170. }
  171. }
  172. }
  173. }
  174. }
  175. // Create channel for build_tx requests
  176. let (build_tx_tx, build_tx_rx) = smol::channel::unbounded();
  177. let self_ = Arc::new(Self {
  178. node: node.clone(),
  179. sg_root,
  180. tasks: OnceLock::new(),
  181. drk: drk.into_ptr(),
  182. build_tx_channel: build_tx_tx,
  183. scan_progress_pub: Publisher::new(),
  184. last_balances: SyncMutex::new(None),
  185. });
  186. // Start background task to process build_tx requests from channel
  187. let me3 = Arc::downgrade(&self_);
  188. let build_tx_processor = 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 =
  207. ex.spawn(
  208. async move { while Self::process_get_default_address(&me2, &method_sub).await {} },
  209. );
  210. let node_ref = node.upgrade().unwrap();
  211. let me2 = Arc::downgrade(&self_);
  212. let method_sub_balances = node_ref.subscribe_method_call("get_balances").unwrap();
  213. let get_balances_task = ex.spawn(async move {
  214. while Self::process_get_balances(&me2, &method_sub_balances).await {}
  215. });
  216. let node_ref = node.upgrade().unwrap();
  217. let me2 = Arc::downgrade(&self_);
  218. let method_sub_tx_status = node_ref.subscribe_method_call("get_tx_status").unwrap();
  219. let get_tx_status_task = ex.spawn(async move {
  220. while Self::process_get_tx_status(&me2, &method_sub_tx_status).await {}
  221. });
  222. let node_ref = node.upgrade().unwrap();
  223. let me2 = Arc::downgrade(&self_);
  224. let method_sub_build_tx = node_ref.subscribe_method_call("build_tx").unwrap();
  225. let build_tx_task =
  226. ex.spawn(
  227. async move { while Self::process_build_tx(&me2, &method_sub_build_tx).await {} },
  228. );
  229. let node_ref = node.upgrade().unwrap();
  230. let me2 = Arc::downgrade(&self_);
  231. let method_sub_broadcast_tx = node_ref.subscribe_method_call("broadcast_tx").unwrap();
  232. let broadcast_tx_task = ex.spawn(async move {
  233. while Self::process_broadcast_tx(&me2, &method_sub_broadcast_tx).await {}
  234. });
  235. let tasks = vec![
  236. get_address_task,
  237. get_balances_task,
  238. get_tx_status_task,
  239. build_tx_task,
  240. broadcast_tx_task,
  241. build_tx_processor,
  242. ];
  243. self_.clone().start(ex.clone(), tasks).await;
  244. Ok(Pimpl::Drk(self_))
  245. }
  246. pub async fn get_default_address(&self) -> Result<String> {
  247. let drk = self.drk.read().await;
  248. let pubkey = drk.default_address().await.map_err(|e| {
  249. e!("Failed to get default address: {e}");
  250. Error::ServiceFailed
  251. })?;
  252. let network = drk.network;
  253. let address: darkfi_sdk::crypto::keypair::Address =
  254. StandardAddress::from_public(network, pubkey).into();
  255. Ok(address.to_string())
  256. }
  257. pub async fn get_balances(&self) -> Result<Vec<(String, TokenId, u64)>> {
  258. let drk = self.drk.read().await;
  259. let balances = drk.money_balance().await.map_err(|e| {
  260. e!("Failed to get money balance: {e}");
  261. Error::ServiceFailed
  262. })?;
  263. let aliases = drk.get_aliases_mapped_by_token().await.map_err(|e| {
  264. e!("Failed to get aliases: {e}");
  265. Error::ServiceFailed
  266. })?;
  267. let mut result: Vec<(String, TokenId, u64)> = Vec::new();
  268. for (token_id_str, balance) in balances {
  269. let alias = aliases.get(&token_id_str).cloned().unwrap_or_else(|| "UNKN".to_string());
  270. let token_id = token_id_str.parse::<TokenId>().unwrap();
  271. result.push((alias, token_id, balance));
  272. }
  273. // Sort by balance
  274. result.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap_or(std::cmp::Ordering::Equal));
  275. Ok(result)
  276. }
  277. /// Emit balances_updated signal with the balances encoded in the payload.
  278. /// Only emits when the encoded balances differ from the last emitted ones.
  279. async fn emit_balances_updated(&self) {
  280. let Some(node) = self.node.upgrade() else { return };
  281. let balances = match self.get_balances().await {
  282. Ok(b) => b,
  283. Err(e) => {
  284. e!("Failed to get balances for balances_updated signal: {e}");
  285. return
  286. }
  287. };
  288. let mut data = vec![];
  289. if let Err(e) = balances.encode(&mut data) {
  290. e!("Failed to encode balances for balances_updated signal: {e}");
  291. return
  292. }
  293. let mut last = self.last_balances.lock();
  294. if let Some(last) = &*last {
  295. if *last == balances {
  296. return
  297. }
  298. }
  299. *last = Some(balances);
  300. let _ = node.trigger("balances_updated", data).await;
  301. }
  302. /// Emit tx_updated signal
  303. async fn emit_tx_updated(&self, state: &TxState) {
  304. if let Some(node) = self.node.upgrade() {
  305. let mut data = vec![];
  306. state.id.clone().encode(&mut data).unwrap();
  307. Some(state.status.text()).encode(&mut data).unwrap();
  308. state.amount.encode(&mut data).unwrap();
  309. state.token_symbol.clone().encode(&mut data).unwrap();
  310. state.recipient.map(|r| r.to_string()).encode(&mut data).unwrap();
  311. let _ = node.trigger("tx_updated", data).await;
  312. }
  313. }
  314. async fn emit_tx_status_updated(&self, status: &TxStatus) {
  315. if let Some(node) = self.node.upgrade() {
  316. let mut data = vec![];
  317. None::<String>.encode(&mut data).unwrap();
  318. Some(status.text()).encode(&mut data).unwrap();
  319. None::<String>.encode(&mut data).unwrap();
  320. None::<String>.encode(&mut data).unwrap();
  321. None::<String>.encode(&mut data).unwrap();
  322. let _ = node.trigger("tx_updated", data).await;
  323. }
  324. }
  325. /// Emit tx_built signal when transaction is built
  326. async fn emit_tx_built(
  327. &self,
  328. amount: String,
  329. token_symbol: String,
  330. recipient: Address,
  331. tx: Transaction,
  332. ) {
  333. if let Some(node) = self.node.upgrade() {
  334. let mut data = vec![];
  335. amount.encode(&mut data).unwrap();
  336. token_symbol.encode(&mut data).unwrap();
  337. recipient.to_string().encode(&mut data).unwrap();
  338. tx.encode(&mut data).unwrap();
  339. let _ = node.trigger("tx_built", data).await;
  340. }
  341. }
  342. /// Emit tx_built_error signal when transaction building fails
  343. async fn emit_tx_built_error(&self, error: String) {
  344. if let Some(node) = self.node.upgrade() {
  345. let mut data = vec![];
  346. error.encode(&mut data).unwrap();
  347. let _ = node.trigger("tx_built_error", data).await;
  348. }
  349. }
  350. async fn process_get_default_address(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  351. let Ok(method_call) = sub.receive().await else {
  352. d!("get_default_address method closed");
  353. return false
  354. };
  355. t!("method called: get_default_address()");
  356. let Some(self_) = me.upgrade() else {
  357. e!("drk plugin destroyed before get_default_address task was stopped!");
  358. if let Some(send_res) = method_call.send_res {
  359. let _ = send_res.send(vec![]).await;
  360. }
  361. return false
  362. };
  363. let address = match self_.get_default_address().await {
  364. Ok(addr) => addr,
  365. Err(e) => {
  366. e!("Failed to get default address: {e}");
  367. if let Some(send_res) = method_call.send_res {
  368. let _ = send_res.send(vec![]).await;
  369. }
  370. return true
  371. }
  372. };
  373. i!("Got default address: {address}");
  374. if let Some(send_res) = method_call.send_res {
  375. let mut cur = Cursor::new(vec![]);
  376. if address.encode(&mut cur).is_ok() {
  377. let _ = send_res.send(cur.into_inner()).await;
  378. } else {
  379. e!("Failed to encode default address");
  380. let _ = send_res.send(vec![]).await;
  381. }
  382. } else {
  383. e!("No send_res channel available");
  384. }
  385. true
  386. }
  387. async fn process_get_balances(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  388. let Ok(method_call) = sub.receive().await else {
  389. d!("get_balances method closed");
  390. return false
  391. };
  392. t!("method called: get_balances()");
  393. let Some(self_) = me.upgrade() else {
  394. e!("drk plugin destroyed before get_balances task was stopped!");
  395. if let Some(send_res) = method_call.send_res {
  396. let _ = send_res.send(vec![]).await;
  397. }
  398. return false
  399. };
  400. let balances = match self_.get_balances().await {
  401. Ok(b) => b,
  402. Err(e) => {
  403. e!("Failed to get balances: {e}");
  404. if let Some(send_res) = method_call.send_res {
  405. let _ = send_res.send(vec![]).await;
  406. }
  407. return true
  408. }
  409. };
  410. if let Some(send_res) = method_call.send_res {
  411. let mut cur = Cursor::new(vec![]);
  412. if balances.encode(&mut cur).is_ok() {
  413. let _ = send_res.send(cur.into_inner()).await;
  414. } else {
  415. e!("Failed to encode balances");
  416. let _ = send_res.send(vec![]).await;
  417. }
  418. } else {
  419. e!("No send_res channel available");
  420. }
  421. true
  422. }
  423. async fn process_get_tx_status(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  424. let Ok(method_call) = sub.receive().await else {
  425. d!("get_tx_history method closed");
  426. return false
  427. };
  428. t!("method called: get_tx_status()");
  429. fn decode_data(data: &[u8]) -> std::io::Result<String> {
  430. let mut cur = Cursor::new(&data);
  431. let tx_id = String::decode(&mut cur)?;
  432. Ok(tx_id)
  433. }
  434. let Ok(tx_id) = decode_data(&method_call.data) else {
  435. d!("get_tx_status() method invalid arg data");
  436. return true
  437. };
  438. let Some(self_) = me.upgrade() else {
  439. e!("drk plugin destroyed before get_tx_status task was stopped!");
  440. if let Some(send_res) = method_call.send_res {
  441. let _ = send_res.send(vec![]).await;
  442. }
  443. return false
  444. };
  445. let drk = self_.drk.read().await;
  446. let Ok((_, status, _block_height, _tx)) = drk.get_tx_history_record(&tx_id).await else {
  447. d!("get_tx_history() method failed to get tx history record");
  448. return true
  449. };
  450. if let Some(send_res) = method_call.send_res {
  451. let mut cur = Cursor::new(vec![]);
  452. let status = match status.as_str() {
  453. "Broadcasted" => TxStatus::Confirming,
  454. "Confirmed" => TxStatus::Confirmed,
  455. _ => TxStatus::Error("unknown status".to_string()),
  456. };
  457. if status.text().encode(&mut cur).is_ok() {
  458. let _ = send_res.send(cur.into_inner()).await;
  459. } else {
  460. e!("Failed to encode balances");
  461. let _ = send_res.send(vec![]).await;
  462. }
  463. } else {
  464. e!("No send_res channel available");
  465. }
  466. true
  467. }
  468. /// Build a transaction without broadcasting it
  469. pub async fn build_tx(
  470. &self,
  471. amount: &str,
  472. token_id: TokenId,
  473. recipient: PublicKey,
  474. ) -> DarkFiResult<Transaction> {
  475. let drk = self.drk.read().await;
  476. drk.transfer(amount, token_id, recipient, None, None, false).await
  477. }
  478. /// Build a transaction from a BuildTxRequest (called by background task)
  479. async fn build_tx_request(
  480. &self,
  481. request: BuildTxRequest,
  482. ) -> DarkFiResult<(Transaction, String, Address, String)> {
  483. let drk = self.drk.read().await;
  484. let aliases = drk.get_aliases_mapped_by_token().await.unwrap_or_default();
  485. let token_symbol =
  486. aliases.get(&request.token_id.to_string()).unwrap_or(&"UNKN".to_string()).to_string();
  487. let recipient: Address =
  488. StandardAddress::from_public(drk.network, request.recipient).into();
  489. let tx = self.build_tx(&request.amount, request.token_id, request.recipient).await?;
  490. Ok((tx, token_symbol, recipient, request.amount))
  491. }
  492. async fn process_build_tx(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  493. let Ok(method_call) = sub.receive().await else {
  494. d!("build_tx method closed");
  495. return false
  496. };
  497. t!("method called: build_tx()");
  498. // Send empty response immediately to unblock the caller
  499. if let Some(send_res) = method_call.send_res {
  500. let _ = send_res.send(vec![]).await;
  501. }
  502. fn decode_data(data: &[u8]) -> std::io::Result<(String, TokenId, PublicKey)> {
  503. let mut cur = Cursor::new(&data);
  504. let amount = String::decode(&mut cur)?;
  505. let token_id = TokenId::decode(&mut cur)?;
  506. let recipient = PublicKey::decode(&mut cur)?;
  507. Ok((amount, token_id, recipient))
  508. }
  509. let Ok((amount, token_id, recipient)) = decode_data(&method_call.data) else {
  510. d!("build_tx() method invalid arg data");
  511. return true
  512. };
  513. let Some(self_) = me.upgrade() else {
  514. e!("drk plugin destroyed before build_tx task was stopped!");
  515. return false
  516. };
  517. // Send request to channel for background processing
  518. let request = BuildTxRequest { amount, token_id, recipient };
  519. let _ = self_.build_tx_channel.send(request).await;
  520. true
  521. }
  522. /// Broadcast a transaction
  523. pub async fn broadcast_tx(&self, tx: Transaction) -> Result<String> {
  524. let drk = self.drk.read().await;
  525. let tx_id = drk.broadcast_tx(&tx, &mut vec![]).await.map_err(|e| {
  526. e!("Failed to broadcast transaction: {e}");
  527. Error::ServiceFailed
  528. })?;
  529. Ok(tx_id)
  530. }
  531. async fn process_broadcast_tx(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
  532. let Ok(method_call) = sub.receive().await else {
  533. d!("broadcast_tx method closed");
  534. return false
  535. };
  536. t!("method called: broadcast_tx()");
  537. let Some(send_res) = method_call.send_res else { return true };
  538. // Send empty response immediately to unblock the caller
  539. let _ = send_res.send(vec![]).await;
  540. let Some(self_) = me.upgrade() else {
  541. e!("drk plugin destroyed before broadcast_tx task was stopped!");
  542. return false
  543. };
  544. let Ok(tx) = Transaction::decode(&mut Cursor::new(&method_call.data)) else {
  545. d!("broadcast_tx() method invalid arg data");
  546. return true
  547. };
  548. let drk = self_.drk.read().await;
  549. if let Err(e) = drk.mark_tx_spend(&tx, &mut vec![]).await {
  550. e!("Failed to mark transaction coins as spent: {e}");
  551. self_
  552. .emit_tx_status_updated(&TxStatus::Error(
  553. "failed to mark coins as spent".to_string(),
  554. ))
  555. .await;
  556. return true
  557. };
  558. let tx_id = match drk.broadcast_tx(&tx, &mut vec![]).await {
  559. Ok(t) => t,
  560. Err(e) => {
  561. e!("Failed to broadcast transaction: {e}");
  562. self_
  563. .emit_tx_status_updated(&TxStatus::Error("failed to broadcast".to_string()))
  564. .await;
  565. return true
  566. }
  567. };
  568. drop(drk);
  569. let state = TxState {
  570. id: Some(tx_id),
  571. status: TxStatus::Confirming,
  572. amount: None,
  573. token_symbol: None,
  574. recipient: None,
  575. };
  576. self_.emit_tx_updated(&state).await;
  577. self_.emit_balances_updated().await;
  578. true
  579. }
  580. async fn start(self: Arc<Self>, ex: ExecutorPtr, tasks: Vec<smol::Task<()>>) {
  581. let endpoint = Url::parse(DARKFID_ENDPOINT).unwrap();
  582. let self2 = self.clone();
  583. let drk = self.drk.clone();
  584. let (shell_sender, shell_receiver) = unbounded();
  585. let ex_ = ex.clone();
  586. let progress_sub = self.scan_progress_pub.clone().subscribe().await;
  587. let scan_progress_task = ex.spawn(async move {
  588. let mut first_height = None;
  589. loop {
  590. let (height, final_height) = progress_sub.receive().await;
  591. if first_height.is_none() {
  592. first_height = Some(height);
  593. }
  594. let progress: f64 = match final_height - first_height.unwrap() {
  595. 0 => 0.,
  596. _ => {
  597. (height - first_height.unwrap()) as f64 /
  598. (final_height - first_height.unwrap()) as f64
  599. }
  600. };
  601. let status: u8 = if progress > 0.5 { 2 } else { 1 };
  602. let Some(node) = self2.node.upgrade() else { continue };
  603. let start_height = first_height.unwrap();
  604. let blocks_scanned = height - start_height;
  605. let total_blocks = final_height - start_height;
  606. let percentage = if total_blocks > 0 {
  607. (blocks_scanned as f32 / total_blocks as f32 * 100.0) as u32
  608. } else {
  609. 0
  610. };
  611. let desc = format!("{}/{} [{}%]", blocks_scanned, total_blocks, percentage);
  612. let _ = node.trigger("connect", serialize(&(status, desc))).await;
  613. }
  614. });
  615. let self2 = self.clone();
  616. // Task that handles the RPC subscription with retry logic
  617. let subscribe_task = ex.spawn(async move {
  618. loop {
  619. i!("Attempting to connect to darkfid daemon at {}", endpoint);
  620. let subscribe_rpc_task = StoppableTask::new();
  621. let shell_sender = shell_sender.clone();
  622. let drk = drk.clone();
  623. let endpoint = endpoint.clone();
  624. let ex = ex_.clone();
  625. let progress_pub = self2.scan_progress_pub.clone();
  626. let _ = self2
  627. .node
  628. .upgrade()
  629. .unwrap()
  630. .trigger("connect", serialize(&(0u8, String::new())))
  631. .await;
  632. if let Err(e) = drk
  633. .read()
  634. .await
  635. .scan_blocks(&mut vec![], Some(&shell_sender), &false, Some(progress_pub))
  636. .await
  637. {
  638. e!("Failed during drk scanning: {e}");
  639. let _ = self2
  640. .node
  641. .upgrade()
  642. .unwrap()
  643. .trigger("connect", serialize(&(0u8, String::new())))
  644. .await;
  645. // Wait before retrying
  646. i!("Retrying connection to darkfid in {} seconds...", DARKFID_RETRY_TIME);
  647. sleep(DARKFID_RETRY_TIME).await;
  648. continue
  649. }
  650. let _ = self2
  651. .node
  652. .upgrade()
  653. .unwrap()
  654. .trigger("connect", serialize(&(3u8, String::new())))
  655. .await;
  656. self2.emit_balances_updated().await;
  657. match subscribe_blocks(
  658. &drk,
  659. subscribe_rpc_task,
  660. shell_sender.clone(),
  661. endpoint,
  662. &ex,
  663. )
  664. .await
  665. {
  666. Ok(()) => {
  667. i!("darkfid subscription closed normally (detached task stopped)");
  668. }
  669. Err(e) => {
  670. e!("darkfid connection failed: {e}");
  671. }
  672. }
  673. let _ = self2
  674. .node
  675. .upgrade()
  676. .unwrap()
  677. .trigger("connect", serialize(&(0u8, String::new())))
  678. .await;
  679. // Wait before retrying
  680. i!("Retrying connection to darkfid in {} seconds...", DARKFID_RETRY_TIME);
  681. sleep(DARKFID_RETRY_TIME).await;
  682. }
  683. });
  684. let self2 = self.clone();
  685. let subscribe_recv_task = ex.spawn(async move {
  686. loop {
  687. let recv = shell_receiver.recv().await;
  688. if let Ok(lines) = recv {
  689. self2.emit_balances_updated().await;
  690. for line in lines.iter() {
  691. i!(line);
  692. }
  693. }
  694. }
  695. });
  696. let mut all_tasks = vec![scan_progress_task, subscribe_task, subscribe_recv_task];
  697. all_tasks.extend(tasks);
  698. self.tasks.set(all_tasks).unwrap();
  699. }
  700. }