use core::future::Future;
use core::ops::Deref;
use core::task;
use crate::chain::chaininterface::BroadcasterInterface;
use crate::chain::ClaimId;
use crate::prelude::*;
use crate::sign::SignerProvider;
use crate::util::async_poll::{dummy_waker, AsyncResult, MaybeSend, MaybeSync};
use crate::util::logger::Logger;
use bitcoin::{Psbt, ScriptBuf, Transaction, TxOut};
use super::BumpTransactionEvent;
use super::{
BumpTransactionEventHandler, CoinSelection, CoinSelectionSource, Input, Utxo, Wallet,
WalletSource,
};
pub trait WalletSourceSync {
fn list_confirmed_utxos(&self) -> Result<Vec<Utxo>, ()>;
fn get_change_script(&self) -> Result<ScriptBuf, ()>;
fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()>;
}
pub(crate) struct WalletSourceSyncWrapper<T: Deref>(T)
where
T::Target: WalletSourceSync;
impl<T: Deref> Deref for WalletSourceSyncWrapper<T>
where
T::Target: WalletSourceSync,
{
type Target = Self;
fn deref(&self) -> &Self {
self
}
}
impl<T: Deref> WalletSource for WalletSourceSyncWrapper<T>
where
T::Target: WalletSourceSync,
{
fn list_confirmed_utxos<'a>(&'a self) -> AsyncResult<'a, Vec<Utxo>, ()> {
let utxos = self.0.list_confirmed_utxos();
Box::pin(async move { utxos })
}
fn get_change_script<'a>(&'a self) -> AsyncResult<'a, ScriptBuf, ()> {
let script = self.0.get_change_script();
Box::pin(async move { script })
}
fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()> {
let signed_psbt = self.0.sign_psbt(psbt);
Box::pin(async move { signed_psbt })
}
}
pub struct WalletSync<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend>
where
W::Target: WalletSourceSync + MaybeSend,
L::Target: Logger + MaybeSend,
{
wallet: Wallet<WalletSourceSyncWrapper<W>, L>,
}
impl<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend> WalletSync<W, L>
where
W::Target: WalletSourceSync + MaybeSend,
L::Target: Logger + MaybeSend,
{
pub fn new(source: W, logger: L) -> Self {
Self { wallet: Wallet::new(WalletSourceSyncWrapper(source), logger) }
}
}
impl<W: Deref + MaybeSync + MaybeSend, L: Deref + MaybeSync + MaybeSend> CoinSelectionSourceSync
for WalletSync<W, L>
where
W::Target: WalletSourceSync + MaybeSend + MaybeSync,
L::Target: Logger + MaybeSend + MaybeSync,
{
fn select_confirmed_utxos(
&self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
) -> Result<CoinSelection, ()> {
let mut fut = self.wallet.select_confirmed_utxos(
claim_id,
must_spend,
must_pay_to,
target_feerate_sat_per_1000_weight,
max_tx_weight,
);
let mut waker = dummy_waker();
let mut ctx = task::Context::from_waker(&mut waker);
match fut.as_mut().poll(&mut ctx) {
task::Poll::Ready(result) => result,
task::Poll::Pending => {
unreachable!(
"Wallet::select_confirmed_utxos should not be pending in a sync context"
);
},
}
}
fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()> {
let mut fut = self.wallet.sign_psbt(psbt);
let mut waker = dummy_waker();
let mut ctx = task::Context::from_waker(&mut waker);
match fut.as_mut().poll(&mut ctx) {
task::Poll::Ready(result) => result,
task::Poll::Pending => {
unreachable!("Wallet::sign_psbt should not be pending in a sync context");
},
}
}
}
pub trait CoinSelectionSourceSync {
fn select_confirmed_utxos(
&self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &[TxOut],
target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
) -> Result<CoinSelection, ()>;
fn sign_psbt(&self, psbt: Psbt) -> Result<Transaction, ()>;
}
struct CoinSelectionSourceSyncWrapper<T: Deref>(T)
where
T::Target: CoinSelectionSourceSync;
impl<T: Deref> Deref for CoinSelectionSourceSyncWrapper<T>
where
T::Target: CoinSelectionSourceSync,
{
type Target = Self;
fn deref(&self) -> &Self {
self
}
}
impl<T: Deref> CoinSelectionSource for CoinSelectionSourceSyncWrapper<T>
where
T::Target: CoinSelectionSourceSync,
{
fn select_confirmed_utxos<'a>(
&'a self, claim_id: ClaimId, must_spend: Vec<Input>, must_pay_to: &'a [TxOut],
target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64,
) -> AsyncResult<'a, CoinSelection, ()> {
let coins = self.0.select_confirmed_utxos(
claim_id,
must_spend,
must_pay_to,
target_feerate_sat_per_1000_weight,
max_tx_weight,
);
Box::pin(async move { coins })
}
fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()> {
let psbt = self.0.sign_psbt(psbt);
Box::pin(async move { psbt })
}
}
pub struct BumpTransactionEventHandlerSync<B: Deref, C: Deref, SP: Deref, L: Deref>
where
B::Target: BroadcasterInterface,
C::Target: CoinSelectionSourceSync,
SP::Target: SignerProvider,
L::Target: Logger,
{
bump_transaction_event_handler:
BumpTransactionEventHandler<B, CoinSelectionSourceSyncWrapper<C>, SP, L>,
}
impl<B: Deref, C: Deref, SP: Deref, L: Deref> BumpTransactionEventHandlerSync<B, C, SP, L>
where
B::Target: BroadcasterInterface,
C::Target: CoinSelectionSourceSync,
SP::Target: SignerProvider,
L::Target: Logger,
{
pub fn new(broadcaster: B, utxo_source: C, signer_provider: SP, logger: L) -> Self {
let bump_transaction_event_handler = BumpTransactionEventHandler::new(
broadcaster,
CoinSelectionSourceSyncWrapper(utxo_source),
signer_provider,
logger,
);
Self { bump_transaction_event_handler }
}
pub fn handle_event(&self, event: &BumpTransactionEvent) {
let mut fut = Box::pin(self.bump_transaction_event_handler.handle_event(event));
let mut waker = dummy_waker();
let mut ctx = task::Context::from_waker(&mut waker);
match fut.as_mut().poll(&mut ctx) {
task::Poll::Ready(result) => result,
task::Poll::Pending => {
unreachable!("BumpTransactionEventHandlerSync::handle_event should not be pending in a sync context");
},
}
}
}