Merge #1081: GUI: change daemon trait to handle async methods
07b47e46db2a8c00d4e7a1ae6004113f87ed758a gui: use tokio::sync::Mutex for embedded daemon (edouardparis)
7b70c8434a978a9235099be2640e292a5debe329 Use async-trait for daemon (edouardparis)
Pull request description:
This a preparatory work in order to have a lianalite backend connection to satisfy the Daemon trait.
This PR also allows us to use tokio::sync::Mutex for the embedded daemon which goes great with the iced tokio runtime.
ACKs for top commit:
edouardparis:
Self-ACK 07b47e46db2a8c00d4e7a1ae6004113f87ed758a
Tree-SHA512: 2d48b07735dc03f127bdddecdd0a4d4f436b2b95d9fccdfcb113ef00c5b8998361606370fdadce7fdee94240b81697704925538cd69904b5a7cbaf3fd03b05cc
This commit is contained in:
commit
d0996d3f5b
1
gui/Cargo.lock
generated
1
gui/Cargo.lock
generated
@ -2643,6 +2643,7 @@ name = "liana_gui"
|
||||
version = "5.0.0"
|
||||
dependencies = [
|
||||
"async-hwi",
|
||||
"async-trait",
|
||||
"backtrace",
|
||||
"base64 0.21.6",
|
||||
"bitcoin_hashes 0.12.0",
|
||||
|
||||
@ -14,6 +14,7 @@ name = "liana-gui"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
async-hwi = "0.0.16"
|
||||
liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false, features = ["nonblocking_shutdown"] }
|
||||
liana_ui = { path = "ui" }
|
||||
|
||||
@ -16,6 +16,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use iced::{clipboard, time, Command, Subscription};
|
||||
use tokio::runtime::Handle;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
pub use liana::{commands::CoinStatus, config::Config as DaemonConfig, miniscript::bitcoin};
|
||||
@ -155,11 +156,12 @@ impl App {
|
||||
fn set_current_panel(&mut self, menu: Menu) -> Command<Message> {
|
||||
match &menu {
|
||||
menu::Menu::TransactionPreSelected(txid) => {
|
||||
if let Ok(Some(tx)) = self
|
||||
.daemon
|
||||
.get_history_txs(&[*txid])
|
||||
.map(|txs| txs.first().cloned())
|
||||
{
|
||||
if let Ok(Some(tx)) = Handle::current().block_on(async {
|
||||
self.daemon
|
||||
.get_history_txs(&[*txid])
|
||||
.await
|
||||
.map(|txs| txs.first().cloned())
|
||||
}) {
|
||||
self.panels.transactions.preselect(tx);
|
||||
self.panels.current = menu;
|
||||
return Command::none();
|
||||
@ -169,11 +171,12 @@ impl App {
|
||||
// Get preselected spend from DB in case it's not yet in the cache.
|
||||
// We only need this single spend as we will go straight to its view and not show the PSBTs list.
|
||||
// In case of any error loading the spend or if it doesn't exist, load PSBTs list in usual way.
|
||||
if let Ok(Some(spend_tx)) = self
|
||||
.daemon
|
||||
.list_spend_transactions(Some(&[*txid]))
|
||||
.map(|txs| txs.first().cloned())
|
||||
{
|
||||
if let Ok(Some(spend_tx)) = Handle::current().block_on(async {
|
||||
self.daemon
|
||||
.list_spend_transactions(Some(&[*txid]))
|
||||
.await
|
||||
.map(|txs| txs.first().cloned())
|
||||
}) {
|
||||
self.panels.psbts.preselect(spend_tx);
|
||||
self.panels.current = menu;
|
||||
return Command::none();
|
||||
@ -201,6 +204,7 @@ impl App {
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
self.panels.current = menu;
|
||||
self.panels
|
||||
.current_mut()
|
||||
@ -217,7 +221,7 @@ impl App {
|
||||
pub fn stop(&mut self) {
|
||||
info!("Close requested");
|
||||
if !self.daemon.is_external() {
|
||||
if let Err(e) = self.daemon.stop() {
|
||||
if let Err(e) = Handle::current().block_on(async { self.daemon.stop().await }) {
|
||||
error!("{}", e);
|
||||
} else {
|
||||
info!("Internal daemon stopped");
|
||||
@ -236,11 +240,12 @@ impl App {
|
||||
Command::perform(
|
||||
async move {
|
||||
// we check every 10 second if the daemon poller is alive
|
||||
daemon.is_alive()?;
|
||||
daemon.is_alive().await?;
|
||||
|
||||
let info = daemon.get_info()?;
|
||||
let info = daemon.get_info().await?;
|
||||
let coins = daemon
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])?;
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await?;
|
||||
Ok(Cache {
|
||||
datadir_path,
|
||||
coins: coins.coins,
|
||||
@ -284,7 +289,7 @@ impl App {
|
||||
daemon_config_path: &PathBuf,
|
||||
cfg: DaemonConfig,
|
||||
) -> Result<(), Error> {
|
||||
self.daemon.stop()?;
|
||||
Handle::current().block_on(async { self.daemon.stop().await })?;
|
||||
let daemon = EmbeddedDaemon::start(cfg)?;
|
||||
self.daemon = Arc::new(daemon);
|
||||
|
||||
|
||||
@ -164,6 +164,7 @@ impl State for CoinsPanel {
|
||||
async move {
|
||||
daemon1
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
@ -173,6 +174,7 @@ impl State for CoinsPanel {
|
||||
async move {
|
||||
let coins = daemon2
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(Error::from)?;
|
||||
let mut targets = HashSet::<LabelItem>::new();
|
||||
@ -181,7 +183,7 @@ impl State for CoinsPanel {
|
||||
targets.insert(LabelItem::Txid(coin.outpoint.txid));
|
||||
targets.insert(LabelItem::Address(coin.address));
|
||||
}
|
||||
daemon2.get_labels(&targets).map_err(|e| e.into())
|
||||
daemon2.get_labels(&targets).await.map_err(|e| e.into())
|
||||
},
|
||||
Message::Labels,
|
||||
),
|
||||
|
||||
@ -66,7 +66,7 @@ impl LabelsEdited {
|
||||
}
|
||||
return Ok(Command::perform(
|
||||
async move {
|
||||
daemon.update_labels(&updated_labels)?;
|
||||
daemon.update_labels(&updated_labels).await?;
|
||||
Ok(updated_labels_str)
|
||||
},
|
||||
Message::LabelsUpdated,
|
||||
|
||||
@ -230,8 +230,9 @@ impl State for Home {
|
||||
return Command::perform(
|
||||
async move {
|
||||
let mut limit = view::home::HISTORY_EVENT_PAGE_SIZE;
|
||||
let mut events =
|
||||
daemon.list_history_txs(0_u32, last_event_date, limit)?;
|
||||
let mut events = daemon
|
||||
.list_history_txs(0_u32, last_event_date, limit)
|
||||
.await?;
|
||||
|
||||
// because gethistory cursor is inclusive and use blocktime
|
||||
// multiple events can occur in the same block.
|
||||
@ -253,7 +254,7 @@ impl State for Home {
|
||||
{
|
||||
// increments of the equivalent of one page more.
|
||||
limit += view::home::HISTORY_EVENT_PAGE_SIZE;
|
||||
events = daemon.list_history_txs(0, last_event_date, limit)?;
|
||||
events = daemon.list_history_txs(0, last_event_date, limit).await?;
|
||||
}
|
||||
Ok(events)
|
||||
},
|
||||
@ -284,13 +285,14 @@ impl State for Home {
|
||||
.unwrap();
|
||||
Command::batch(vec![
|
||||
Command::perform(
|
||||
async move { daemon3.list_pending_txs().map_err(|e| e.into()) },
|
||||
async move { daemon3.list_pending_txs().await.map_err(|e| e.into()) },
|
||||
Message::PendingTransactions,
|
||||
),
|
||||
Command::perform(
|
||||
async move {
|
||||
daemon1
|
||||
.list_history_txs(0, now, view::home::HISTORY_EVENT_PAGE_SIZE)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::HistoryTransactions,
|
||||
@ -299,6 +301,7 @@ impl State for Home {
|
||||
async move {
|
||||
daemon2
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
|
||||
@ -173,6 +173,7 @@ impl PsbtState {
|
||||
async move {
|
||||
daemon
|
||||
.list_coins(&[CoinStatus::Spending], &outpoints)
|
||||
.await
|
||||
.map(|res| {
|
||||
res.coins
|
||||
.iter()
|
||||
@ -275,8 +276,8 @@ impl Action for SaveAction {
|
||||
}
|
||||
return Command::perform(
|
||||
async move {
|
||||
daemon.update_spend_tx(&psbt)?;
|
||||
daemon.update_labels(&labels).map_err(|e| e.into())
|
||||
daemon.update_spend_tx(&psbt).await?;
|
||||
daemon.update_labels(&labels).await.map_err(|e| e.into())
|
||||
},
|
||||
Message::Updated,
|
||||
);
|
||||
@ -323,6 +324,7 @@ impl Action for BroadcastAction {
|
||||
async move {
|
||||
daemon
|
||||
.broadcast_spend_tx(&psbt.unsigned_tx.txid())
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::Updated,
|
||||
@ -375,6 +377,7 @@ impl Action for DeleteAction {
|
||||
async move {
|
||||
daemon
|
||||
.delete_spend_tx(&psbt.unsigned_tx.txid())
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::Updated,
|
||||
@ -482,7 +485,7 @@ impl Action for SignAction {
|
||||
merge_signatures(&mut tx.psbt, &psbt);
|
||||
if self.is_saved {
|
||||
return Command::perform(
|
||||
async move { daemon.update_spend_tx(&psbt).map_err(|e| e.into()) },
|
||||
async move { daemon.update_spend_tx(&psbt).await.map_err(|e| e.into()) },
|
||||
Message::Updated,
|
||||
);
|
||||
// If the spend transaction was never saved before, then both the psbt and
|
||||
@ -496,8 +499,8 @@ impl Action for SignAction {
|
||||
}
|
||||
return Command::perform(
|
||||
async move {
|
||||
daemon.update_spend_tx(&psbt)?;
|
||||
daemon.update_labels(&labels).map_err(|e| e.into())
|
||||
daemon.update_spend_tx(&psbt).await?;
|
||||
daemon.update_labels(&labels).await.map_err(|e| e.into())
|
||||
},
|
||||
Message::Updated,
|
||||
);
|
||||
@ -727,7 +730,7 @@ impl Action for UpdateAction {
|
||||
self.error = None;
|
||||
let updated = Psbt::from_str(&self.updated.value).expect("Already checked");
|
||||
return Command::perform(
|
||||
async move { daemon.update_spend_tx(&updated).map_err(|e| e.into()) },
|
||||
async move { daemon.update_spend_tx(&updated).await.map_err(|e| e.into()) },
|
||||
Message::Updated,
|
||||
);
|
||||
}
|
||||
|
||||
@ -128,7 +128,12 @@ impl State for PsbtsPanel {
|
||||
self.import_tx = None;
|
||||
let daemon = daemon.clone();
|
||||
Command::perform(
|
||||
async move { daemon.list_spend_transactions(None).map_err(|e| e.into()) },
|
||||
async move {
|
||||
daemon
|
||||
.list_spend_transactions(None)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::SpendTxs,
|
||||
)
|
||||
}
|
||||
@ -194,7 +199,12 @@ impl ImportPsbtModal {
|
||||
self.error = None;
|
||||
let imported = Psbt::from_str(&self.imported.value).expect("Already checked");
|
||||
return Command::perform(
|
||||
async move { daemon.update_spend_tx(&imported).map_err(|e| e.into()) },
|
||||
async move {
|
||||
daemon
|
||||
.update_spend_tx(&imported)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::Updated,
|
||||
);
|
||||
}
|
||||
|
||||
@ -161,6 +161,7 @@ impl State for ReceivePanel {
|
||||
async move {
|
||||
daemon
|
||||
.get_new_address()
|
||||
.await
|
||||
.map(|res| (res.address, res.derivation_index))
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
@ -200,6 +201,7 @@ impl State for ReceivePanel {
|
||||
async move {
|
||||
daemon
|
||||
.get_new_address()
|
||||
.await
|
||||
.map(|res| (res.address, res.derivation_index))
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
|
||||
@ -157,14 +157,19 @@ impl State for RecoveryPanel {
|
||||
let network = cache.network;
|
||||
return Command::perform(
|
||||
async move {
|
||||
let psbt = daemon.create_recovery(address, feerate_vb, sequence)?;
|
||||
let psbt = daemon
|
||||
.create_recovery(address, feerate_vb, sequence)
|
||||
.await?;
|
||||
let outpoints: Vec<_> = psbt
|
||||
.unsigned_tx
|
||||
.input
|
||||
.iter()
|
||||
.map(|txin| txin.previous_output)
|
||||
.collect();
|
||||
let coins = daemon.list_coins(&[], &outpoints).map(|res| res.coins)?;
|
||||
let coins = daemon
|
||||
.list_coins(&[], &outpoints)
|
||||
.await
|
||||
.map(|res| res.coins)?;
|
||||
Ok(SpendTx::new(
|
||||
None,
|
||||
psbt,
|
||||
@ -208,6 +213,7 @@ impl State for RecoveryPanel {
|
||||
async move {
|
||||
daemon
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
|
||||
@ -420,7 +420,9 @@ impl RescanSetting {
|
||||
info!("Asking deamon to rescan with timestamp: {}", t);
|
||||
return Command::perform(
|
||||
async move {
|
||||
daemon.start_rescan(t.try_into().expect("t cannot be inferior to 0 otherwise genesis block timestam is chosen")).map_err(|e| e.into())
|
||||
daemon.start_rescan(t.try_into().expect("t cannot be inferior to 0 otherwise genesis block timestamp is chosen"))
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::StartRescan,
|
||||
);
|
||||
|
||||
@ -164,7 +164,7 @@ impl State for AboutSettingsState {
|
||||
_wallet: Arc<Wallet>,
|
||||
) -> Command<Message> {
|
||||
Command::perform(
|
||||
async move { daemon.get_info().map_err(|e| e.into()) },
|
||||
async move { daemon.get_info().await.map_err(|e| e.into()) },
|
||||
Message::Info,
|
||||
)
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ impl State for WalletSettingsState {
|
||||
self.keys_aliases = Self::keys_aliases(&wallet);
|
||||
self.wallet = wallet;
|
||||
Command::perform(
|
||||
async move { daemon.get_info().map_err(|e| e.into()) },
|
||||
async move { daemon.get_info().await.map_err(|e| e.into()) },
|
||||
Message::Info,
|
||||
)
|
||||
}
|
||||
|
||||
@ -127,6 +127,7 @@ impl State for CreateSpendPanel {
|
||||
async move {
|
||||
daemon1
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
@ -136,6 +137,7 @@ impl State for CreateSpendPanel {
|
||||
async move {
|
||||
let coins = daemon
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)
|
||||
.map_err(Error::from)?;
|
||||
let mut targets = HashSet::<LabelItem>::new();
|
||||
@ -143,7 +145,7 @@ impl State for CreateSpendPanel {
|
||||
targets.insert(LabelItem::OutPoint(coin.outpoint));
|
||||
targets.insert(LabelItem::Txid(coin.outpoint.txid));
|
||||
}
|
||||
daemon2.get_labels(&targets).map_err(|e| e.into())
|
||||
daemon2.get_labels(&targets).await.map_err(|e| e.into())
|
||||
},
|
||||
Message::Labels,
|
||||
),
|
||||
|
||||
@ -307,13 +307,16 @@ impl DefineSpend {
|
||||
};
|
||||
|
||||
let feerate_vb = self.feerate.value.parse::<u64>().expect("Checked before");
|
||||
|
||||
match daemon.create_spend_tx(
|
||||
&outpoints,
|
||||
&destinations,
|
||||
feerate_vb,
|
||||
Some(change_address.clone()),
|
||||
) {
|
||||
match tokio::runtime::Handle::current().block_on(async {
|
||||
daemon
|
||||
.create_spend_tx(
|
||||
&outpoints,
|
||||
&destinations,
|
||||
feerate_vb,
|
||||
Some(change_address.clone()),
|
||||
)
|
||||
.await
|
||||
}) {
|
||||
Ok(CreateSpendResult::Success { psbt, .. }) => {
|
||||
self.warning = None;
|
||||
if !self.is_user_coin_selection {
|
||||
@ -483,6 +486,7 @@ impl Step for DefineSpend {
|
||||
async move {
|
||||
daemon
|
||||
.create_spend_tx(&inputs, &outputs, feerate_vb, None)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
.and_then(|res| match res {
|
||||
CreateSpendResult::Success { psbt, warnings } => {
|
||||
|
||||
@ -160,6 +160,7 @@ impl State for TransactionsPanel {
|
||||
async move {
|
||||
daemon
|
||||
.list_coins(&[CoinStatus::Spending], &outpoints)
|
||||
.await
|
||||
.map(|res| {
|
||||
res.coins
|
||||
.iter()
|
||||
@ -202,7 +203,8 @@ impl State for TransactionsPanel {
|
||||
return Command::perform(
|
||||
async move {
|
||||
let mut limit = view::home::HISTORY_EVENT_PAGE_SIZE;
|
||||
let mut txs = daemon.list_history_txs(0_u32, last_tx_date, limit)?;
|
||||
let mut txs =
|
||||
daemon.list_history_txs(0_u32, last_tx_date, limit).await?;
|
||||
|
||||
// because gethistory cursor is inclusive and use blocktime
|
||||
// multiple txs can occur in the same block.
|
||||
@ -224,7 +226,7 @@ impl State for TransactionsPanel {
|
||||
{
|
||||
// increments of the equivalent of one page more.
|
||||
limit += view::home::HISTORY_EVENT_PAGE_SIZE;
|
||||
txs = daemon.list_history_txs(0, last_tx_date, limit)?;
|
||||
txs = daemon.list_history_txs(0, last_tx_date, limit).await?;
|
||||
}
|
||||
Ok(txs)
|
||||
},
|
||||
@ -257,13 +259,14 @@ impl State for TransactionsPanel {
|
||||
.unwrap();
|
||||
Command::batch(vec![
|
||||
Command::perform(
|
||||
async move { daemon2.list_pending_txs().map_err(|e| e.into()) },
|
||||
async move { daemon2.list_pending_txs().await.map_err(|e| e.into()) },
|
||||
Message::PendingTransactions,
|
||||
),
|
||||
Command::perform(
|
||||
async move {
|
||||
daemon1
|
||||
.list_history_txs(0, now, view::home::HISTORY_EVENT_PAGE_SIZE)
|
||||
.await
|
||||
.map_err(|e| e.into())
|
||||
},
|
||||
Message::HistoryTransactions,
|
||||
@ -405,7 +408,10 @@ async fn rbf(
|
||||
feerate_vb: Option<u64>,
|
||||
) -> Result<Txid, Error> {
|
||||
let previous_txid = previous_tx.tx.txid();
|
||||
let psbt = match daemon.rbf_psbt(&previous_txid, is_cancel, feerate_vb)? {
|
||||
let psbt = match daemon
|
||||
.rbf_psbt(&previous_txid, is_cancel, feerate_vb)
|
||||
.await?
|
||||
{
|
||||
CreateSpendResult::Success { psbt, .. } => psbt,
|
||||
CreateSpendResult::InsufficientFunds { missing } => {
|
||||
return Err(
|
||||
@ -445,9 +451,9 @@ async fn rbf(
|
||||
}
|
||||
}
|
||||
|
||||
daemon.update_labels(&labels)?;
|
||||
daemon.update_labels(&labels).await?;
|
||||
}
|
||||
|
||||
daemon.update_spend_tx(&psbt)?;
|
||||
daemon.update_spend_tx(&psbt).await?;
|
||||
Ok(psbt.unsigned_tx.txid())
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::fmt::Debug;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use liana::commands::{CoinStatus, CreateRecoveryResult};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -52,7 +53,8 @@ impl<C: Client> Lianad<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
#[async_trait]
|
||||
impl<C: Client + Send + Sync + Debug> Daemon for Lianad<C> {
|
||||
fn is_external(&self) -> bool {
|
||||
true
|
||||
}
|
||||
@ -61,23 +63,25 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
None
|
||||
}
|
||||
|
||||
fn is_alive(&self) -> Result<(), DaemonError> {
|
||||
async fn is_alive(&self) -> Result<(), DaemonError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop(&self) -> Result<(), DaemonError> {
|
||||
unreachable!("GUI should not ask external client to stop")
|
||||
async fn stop(&self) -> Result<(), DaemonError> {
|
||||
Err(DaemonError::Unexpected(
|
||||
"GUI should not ask external client to stop".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||
async fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||
self.call("getinfo", Option::<Request>::None)
|
||||
}
|
||||
|
||||
fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
||||
async fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
||||
self.call("getnewaddress", Option::<Request>::None)
|
||||
}
|
||||
|
||||
fn list_coins(
|
||||
async fn list_coins(
|
||||
&self,
|
||||
statuses: &[CoinStatus],
|
||||
outpoints: &[OutPoint],
|
||||
@ -91,11 +95,11 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
)
|
||||
}
|
||||
|
||||
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
async fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
self.call("listspendtxs", Option::<Request>::None)
|
||||
}
|
||||
|
||||
fn create_spend_tx(
|
||||
async fn create_spend_tx(
|
||||
&self,
|
||||
coins_outpoints: &[OutPoint],
|
||||
destinations: &HashMap<Address<address::NetworkUnchecked>, u64>,
|
||||
@ -113,7 +117,7 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
self.call("createspend", Some(input))
|
||||
}
|
||||
|
||||
fn rbf_psbt(
|
||||
async fn rbf_psbt(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
is_cancel: bool,
|
||||
@ -126,30 +130,30 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
self.call("rbfpsbt", Some(input))
|
||||
}
|
||||
|
||||
fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
||||
async fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
||||
let spend_tx = psbt.to_string();
|
||||
let _res: serde_json::value::Value = self.call("updatespend", Some(vec![spend_tx]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
async fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
let _res: serde_json::value::Value =
|
||||
self.call("delspendtx", Some(vec![txid.to_string()]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
async fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
let _res: serde_json::value::Value =
|
||||
self.call("broadcastspend", Some(vec![txid.to_string()]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
||||
async fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
||||
let _res: serde_json::value::Value = self.call("startrescan", Some(vec![t]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list_confirmed_txs(
|
||||
async fn list_confirmed_txs(
|
||||
&self,
|
||||
start: u32,
|
||||
end: u32,
|
||||
@ -161,11 +165,11 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
)
|
||||
}
|
||||
|
||||
fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
||||
async fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
||||
self.call("listtransactions", Some(vec![txids]))
|
||||
}
|
||||
|
||||
fn create_recovery(
|
||||
async fn create_recovery(
|
||||
&self,
|
||||
address: Address<address::NetworkUnchecked>,
|
||||
feerate_vb: u64,
|
||||
@ -178,7 +182,7 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
Ok(res.psbt)
|
||||
}
|
||||
|
||||
fn get_labels(
|
||||
async fn get_labels(
|
||||
&self,
|
||||
items: &HashSet<LabelItem>,
|
||||
) -> Result<HashMap<String, String>, DaemonError> {
|
||||
@ -187,7 +191,10 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
||||
Ok(res.labels)
|
||||
}
|
||||
|
||||
fn update_labels(&self, items: &HashMap<LabelItem, Option<String>>) -> Result<(), DaemonError> {
|
||||
async fn update_labels(
|
||||
&self,
|
||||
items: &HashMap<LabelItem, Option<String>>,
|
||||
) -> Result<(), DaemonError> {
|
||||
let labels: HashMap<String, Option<String>> =
|
||||
HashMap::from_iter(items.iter().map(|(a, l)| (a.to_string(), l.clone())));
|
||||
let _res: serde_json::value::Value = self.call("updatelabels", Some(vec![labels]))?;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Mutex;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use super::{model::*, Daemon, DaemonError};
|
||||
use async_trait::async_trait;
|
||||
use liana::{
|
||||
commands::{CoinStatus, LabelItem},
|
||||
config::Config,
|
||||
@ -23,11 +24,11 @@ impl EmbeddedDaemon {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn command<T, F>(&self, method: F) -> Result<T, DaemonError>
|
||||
pub async fn command<T, F>(&self, method: F) -> Result<T, DaemonError>
|
||||
where
|
||||
F: FnOnce(&DaemonControl) -> Result<T, DaemonError>,
|
||||
{
|
||||
match self.handle.lock()?.as_ref() {
|
||||
match self.handle.lock().await.as_ref() {
|
||||
Some(DaemonHandle::Controller { control, .. }) => method(control),
|
||||
None => Err(DaemonError::DaemonStopped),
|
||||
}
|
||||
@ -46,6 +47,7 @@ impl std::fmt::Debug for EmbeddedDaemon {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Daemon for EmbeddedDaemon {
|
||||
fn is_external(&self) -> bool {
|
||||
false
|
||||
@ -55,8 +57,8 @@ impl Daemon for EmbeddedDaemon {
|
||||
Some(&self.config)
|
||||
}
|
||||
|
||||
fn is_alive(&self) -> Result<(), DaemonError> {
|
||||
let mut handle = self.handle.lock()?;
|
||||
async fn is_alive(&self) -> Result<(), DaemonError> {
|
||||
let mut handle = self.handle.lock().await;
|
||||
if let Some(h) = handle.as_ref() {
|
||||
if h.is_alive() {
|
||||
return Ok(());
|
||||
@ -70,8 +72,8 @@ impl Daemon for EmbeddedDaemon {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop(&self) -> Result<(), DaemonError> {
|
||||
let mut handle = self.handle.lock()?;
|
||||
async fn stop(&self) -> Result<(), DaemonError> {
|
||||
let mut handle = self.handle.lock().await;
|
||||
if let Some(h) = handle.take() {
|
||||
h.stop()
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))?;
|
||||
@ -79,44 +81,48 @@ impl Daemon for EmbeddedDaemon {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.get_info()))
|
||||
async fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.get_info())).await
|
||||
}
|
||||
|
||||
fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.get_new_address()))
|
||||
async fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.get_new_address())).await
|
||||
}
|
||||
|
||||
fn list_coins(
|
||||
async fn list_coins(
|
||||
&self,
|
||||
statuses: &[CoinStatus],
|
||||
outpoints: &[OutPoint],
|
||||
) -> Result<ListCoinsResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.list_coins(statuses, outpoints)))
|
||||
.await
|
||||
}
|
||||
|
||||
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
async fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon
|
||||
.list_spend(None)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn list_confirmed_txs(
|
||||
async fn list_confirmed_txs(
|
||||
&self,
|
||||
start: u32,
|
||||
end: u32,
|
||||
limit: u64,
|
||||
) -> Result<ListTransactionsResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.list_confirmed_transactions(start, end, limit)))
|
||||
.await
|
||||
}
|
||||
|
||||
fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
||||
async fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.list_transactions(txids)))
|
||||
.await
|
||||
}
|
||||
|
||||
fn create_spend_tx(
|
||||
async fn create_spend_tx(
|
||||
&self,
|
||||
coins_outpoints: &[OutPoint],
|
||||
destinations: &HashMap<Address<address::NetworkUnchecked>, u64>,
|
||||
@ -128,9 +134,10 @@ impl Daemon for EmbeddedDaemon {
|
||||
.create_spend(destinations, coins_outpoints, feerate_vb, change_address)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn rbf_psbt(
|
||||
async fn rbf_psbt(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
is_cancel: bool,
|
||||
@ -141,40 +148,45 @@ impl Daemon for EmbeddedDaemon {
|
||||
.rbf_psbt(txid, is_cancel, feerate_vb)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
||||
async fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon
|
||||
.update_spend(psbt.clone())
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
async fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon.delete_spend(txid);
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
async fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon
|
||||
.broadcast_spend(txid)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
||||
async fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon
|
||||
.start_rescan(t)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn create_recovery(
|
||||
async fn create_recovery(
|
||||
&self,
|
||||
address: Address<address::NetworkUnchecked>,
|
||||
feerate_vb: u64,
|
||||
@ -186,19 +198,25 @@ impl Daemon for EmbeddedDaemon {
|
||||
.map(|res| res.psbt)
|
||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
fn get_labels(
|
||||
async fn get_labels(
|
||||
&self,
|
||||
items: &HashSet<LabelItem>,
|
||||
) -> Result<HashMap<String, String>, DaemonError> {
|
||||
self.command(|daemon| Ok(daemon.get_labels(items).labels))
|
||||
.await
|
||||
}
|
||||
|
||||
fn update_labels(&self, items: &HashMap<LabelItem, Option<String>>) -> Result<(), DaemonError> {
|
||||
async fn update_labels(
|
||||
&self,
|
||||
items: &HashMap<LabelItem, Option<String>>,
|
||||
) -> Result<(), DaemonError> {
|
||||
self.command(|daemon| {
|
||||
daemon.update_labels(items);
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ use std::fmt::Debug;
|
||||
use std::io::ErrorKind;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use liana::{
|
||||
commands::{CoinStatus, LabelItem, TransactionInfo},
|
||||
config::Config,
|
||||
@ -50,67 +52,70 @@ impl std::fmt::Display for DaemonError {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Daemon: Debug {
|
||||
fn is_external(&self) -> bool;
|
||||
fn config(&self) -> Option<&Config>;
|
||||
fn is_alive(&self) -> Result<(), DaemonError>;
|
||||
fn stop(&self) -> Result<(), DaemonError>;
|
||||
fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>;
|
||||
fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
|
||||
fn list_coins(
|
||||
async fn is_alive(&self) -> Result<(), DaemonError>;
|
||||
async fn stop(&self) -> Result<(), DaemonError>;
|
||||
async fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>;
|
||||
async fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
|
||||
async fn list_coins(
|
||||
&self,
|
||||
statuses: &[CoinStatus],
|
||||
outpoints: &[OutPoint],
|
||||
) -> Result<model::ListCoinsResult, DaemonError>;
|
||||
fn list_spend_txs(&self) -> Result<model::ListSpendResult, DaemonError>;
|
||||
fn create_spend_tx(
|
||||
async fn list_spend_txs(&self) -> Result<model::ListSpendResult, DaemonError>;
|
||||
async fn create_spend_tx(
|
||||
&self,
|
||||
coins_outpoints: &[OutPoint],
|
||||
destinations: &HashMap<Address<address::NetworkUnchecked>, u64>,
|
||||
feerate_vb: u64,
|
||||
change_address: Option<Address<address::NetworkUnchecked>>,
|
||||
) -> Result<model::CreateSpendResult, DaemonError>;
|
||||
fn rbf_psbt(
|
||||
async fn rbf_psbt(
|
||||
&self,
|
||||
txid: &Txid,
|
||||
is_cancel: bool,
|
||||
feerate_vb: Option<u64>,
|
||||
) -> Result<model::CreateSpendResult, DaemonError>;
|
||||
fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError>;
|
||||
fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError>;
|
||||
fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError>;
|
||||
fn start_rescan(&self, t: u32) -> Result<(), DaemonError>;
|
||||
fn list_confirmed_txs(
|
||||
async fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError>;
|
||||
async fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError>;
|
||||
async fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError>;
|
||||
async fn start_rescan(&self, t: u32) -> Result<(), DaemonError>;
|
||||
async fn list_confirmed_txs(
|
||||
&self,
|
||||
_start: u32,
|
||||
_end: u32,
|
||||
_limit: u64,
|
||||
) -> Result<model::ListTransactionsResult, DaemonError>;
|
||||
fn create_recovery(
|
||||
async fn create_recovery(
|
||||
&self,
|
||||
address: Address<address::NetworkUnchecked>,
|
||||
feerate_vb: u64,
|
||||
sequence: Option<u16>,
|
||||
) -> Result<Psbt, DaemonError>;
|
||||
fn list_txs(&self, txid: &[Txid]) -> Result<model::ListTransactionsResult, DaemonError>;
|
||||
fn get_labels(
|
||||
async fn list_txs(&self, txid: &[Txid]) -> Result<model::ListTransactionsResult, DaemonError>;
|
||||
async fn get_labels(
|
||||
&self,
|
||||
labels: &HashSet<LabelItem>,
|
||||
) -> Result<HashMap<String, String>, DaemonError>;
|
||||
fn update_labels(&self, labels: &HashMap<LabelItem, Option<String>>)
|
||||
-> Result<(), DaemonError>;
|
||||
async fn update_labels(
|
||||
&self,
|
||||
labels: &HashMap<LabelItem, Option<String>>,
|
||||
) -> Result<(), DaemonError>;
|
||||
|
||||
// List spend transactions, optionally filtered to the specified `txids`.
|
||||
// Set `txids` to `None` for no filter (passing an empty slice returns no transactions).
|
||||
fn list_spend_transactions(
|
||||
async fn list_spend_transactions(
|
||||
&self,
|
||||
txids: Option<&[Txid]>,
|
||||
) -> Result<Vec<model::SpendTx>, DaemonError> {
|
||||
let info = self.get_info()?;
|
||||
let info = self.get_info().await?;
|
||||
let mut spend_txs = Vec::new();
|
||||
let curve = secp256k1::Secp256k1::verification_only();
|
||||
// TODO: Use filters in `list_spend_txs` command.
|
||||
let mut txs = self.list_spend_txs()?.spend_txs;
|
||||
let mut txs = self.list_spend_txs().await?.spend_txs;
|
||||
if let Some(txids) = txids {
|
||||
txs.retain(|tx| txids.contains(&tx.psbt.unsigned_tx.txid()));
|
||||
}
|
||||
@ -125,7 +130,7 @@ pub trait Daemon: Debug {
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect();
|
||||
let coins = self.list_coins(&[], &outpoints)?.coins;
|
||||
let coins = self.list_coins(&[], &outpoints).await?.coins;
|
||||
for tx in txs {
|
||||
let coins = coins
|
||||
.iter()
|
||||
@ -148,7 +153,7 @@ pub trait Daemon: Debug {
|
||||
info.network,
|
||||
));
|
||||
}
|
||||
load_labels(self, &mut spend_txs)?;
|
||||
load_labels(self, &mut spend_txs).await?;
|
||||
spend_txs.sort_by(|a, b| {
|
||||
if a.status == b.status {
|
||||
// last updated first
|
||||
@ -161,11 +166,11 @@ pub trait Daemon: Debug {
|
||||
Ok(spend_txs)
|
||||
}
|
||||
|
||||
fn txs_to_historytxs(
|
||||
async fn txs_to_historytxs(
|
||||
&self,
|
||||
txs: Vec<TransactionInfo>,
|
||||
) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
|
||||
let info = self.get_info()?;
|
||||
let info = self.get_info().await?;
|
||||
let outpoints: Vec<_> = txs
|
||||
.iter()
|
||||
.flat_map(|tx| {
|
||||
@ -184,7 +189,7 @@ pub trait Daemon: Debug {
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
let coins = self.list_coins(&[], &outpoints)?.coins;
|
||||
let coins = self.list_coins(&[], &outpoints).await?.coins;
|
||||
let mut txs = txs
|
||||
.into_iter()
|
||||
.map(|tx| {
|
||||
@ -212,34 +217,38 @@ pub trait Daemon: Debug {
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
load_labels(self, &mut txs)?;
|
||||
load_labels(self, &mut txs).await?;
|
||||
Ok(txs)
|
||||
}
|
||||
|
||||
fn list_history_txs(
|
||||
async fn list_history_txs(
|
||||
&self,
|
||||
start: u32,
|
||||
end: u32,
|
||||
limit: u64,
|
||||
) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
|
||||
let txs = self.list_confirmed_txs(start, end, limit)?.transactions;
|
||||
self.txs_to_historytxs(txs)
|
||||
let txs = self
|
||||
.list_confirmed_txs(start, end, limit)
|
||||
.await?
|
||||
.transactions;
|
||||
self.txs_to_historytxs(txs).await
|
||||
}
|
||||
|
||||
fn get_history_txs(
|
||||
async fn get_history_txs(
|
||||
&self,
|
||||
txids: &[Txid],
|
||||
) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
|
||||
let txs = self.list_txs(txids)?.transactions;
|
||||
self.txs_to_historytxs(txs)
|
||||
let txs = self.list_txs(txids).await?.transactions;
|
||||
self.txs_to_historytxs(txs).await
|
||||
}
|
||||
|
||||
fn list_pending_txs(&self) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
|
||||
let info = self.get_info()?;
|
||||
async fn list_pending_txs(&self) -> Result<Vec<model::HistoryTransaction>, DaemonError> {
|
||||
let info = self.get_info().await?;
|
||||
// We want coins that are inputs to and/or outputs of a pending tx,
|
||||
// which can only be unconfirmed and spending coins.
|
||||
let coins = self
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Spending], &[])?
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Spending], &[])
|
||||
.await?
|
||||
.coins;
|
||||
let mut txids: Vec<Txid> = Vec::new();
|
||||
for coin in &coins {
|
||||
@ -254,7 +263,7 @@ pub trait Daemon: Debug {
|
||||
}
|
||||
}
|
||||
|
||||
let txs = self.list_txs(&txids)?.transactions;
|
||||
let txs = self.list_txs(&txids).await?.transactions;
|
||||
let mut txs = txs
|
||||
.into_iter()
|
||||
.map(|tx| {
|
||||
@ -283,12 +292,12 @@ pub trait Daemon: Debug {
|
||||
})
|
||||
.collect();
|
||||
|
||||
load_labels(self, &mut txs)?;
|
||||
load_labels(self, &mut txs).await?;
|
||||
Ok(txs)
|
||||
}
|
||||
}
|
||||
|
||||
fn load_labels<T: model::Labelled, D: Daemon + ?Sized>(
|
||||
async fn load_labels<T: model::Labelled, D: Daemon + ?Sized>(
|
||||
daemon: &D,
|
||||
targets: &mut Vec<T>,
|
||||
) -> Result<(), DaemonError> {
|
||||
@ -303,7 +312,8 @@ fn load_labels<T: model::Labelled, D: Daemon + ?Sized>(
|
||||
}
|
||||
let labels = HashMap::from_iter(
|
||||
daemon
|
||||
.get_labels(&items)?
|
||||
.get_labels(&items)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, Some(v))),
|
||||
);
|
||||
|
||||
@ -6,6 +6,7 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use iced::{Alignment, Command, Length, Subscription};
|
||||
use tokio::runtime::Handle;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use liana::{
|
||||
@ -229,7 +230,7 @@ impl Loader {
|
||||
if let Step::Syncing { daemon, .. } = &mut self.step {
|
||||
if !daemon.is_external() {
|
||||
info!("Stopping internal daemon...");
|
||||
if let Err(e) = daemon.stop() {
|
||||
if let Err(e) = Handle::current().block_on(async { daemon.stop().await }) {
|
||||
warn!("Internal daemon failed to stop: {}", e);
|
||||
} else {
|
||||
info!("Internal daemon stopped");
|
||||
@ -373,6 +374,7 @@ pub async fn load_application(
|
||||
|
||||
let coins = daemon
|
||||
.list_coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[])
|
||||
.await
|
||||
.map(|res| res.coins)?;
|
||||
|
||||
let cache = Cache {
|
||||
@ -484,7 +486,7 @@ async fn connect(socket_path: PathBuf) -> Result<Arc<dyn Daemon + Sync + Send>,
|
||||
let daemon = Lianad::new(client);
|
||||
|
||||
debug!("Searching for external daemon");
|
||||
daemon.get_info()?;
|
||||
daemon.get_info().await?;
|
||||
info!("Connected to external daemon");
|
||||
|
||||
Ok(Arc::new(daemon))
|
||||
@ -532,7 +534,7 @@ async fn sync(
|
||||
if sleep {
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
}
|
||||
daemon.get_info()
|
||||
daemon.get_info().await
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user