[bdk_chain_redesign] List chain data methods can be try/non-try
Methods that list chain data have try and non-try versions. Both of these versions now return an `Iterator`. * Try versions return `Iterator<Item = Result>`. * Non-try versions require the `ChainOracle` implementation to be `ChainOracle<Error = Infallible>`.
This commit is contained in:
parent
43b648fee0
commit
784cd34e3d
@ -61,7 +61,10 @@ use crate::{
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use bitcoin::{OutPoint, Transaction, TxOut, Txid};
|
||||
use core::ops::{Deref, RangeInclusive};
|
||||
use core::{
|
||||
convert::Infallible,
|
||||
ops::{Deref, RangeInclusive},
|
||||
};
|
||||
|
||||
/// A graph of transactions and spends.
|
||||
///
|
||||
@ -492,7 +495,7 @@ impl<A: BlockAnchor> TxGraph<A> {
|
||||
/// Determines whether a transaction of `txid` is in the best chain.
|
||||
///
|
||||
/// TODO: Also return conflicting tx list, ordered by last_seen.
|
||||
pub fn get_position_in_chain<C>(
|
||||
pub fn try_get_chain_position<C>(
|
||||
&self,
|
||||
chain: C,
|
||||
txid: Txid,
|
||||
@ -544,7 +547,15 @@ impl<A: BlockAnchor> TxGraph<A> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_spend_in_chain<C>(
|
||||
pub fn get_chain_position<C>(&self, chain: C, txid: Txid) -> Option<ObservedIn<&A>>
|
||||
where
|
||||
C: ChainOracle<Error = Infallible>,
|
||||
{
|
||||
self.try_get_chain_position(chain, txid)
|
||||
.expect("error is infallible")
|
||||
}
|
||||
|
||||
pub fn try_get_spend_in_chain<C>(
|
||||
&self,
|
||||
chain: C,
|
||||
outpoint: OutPoint,
|
||||
@ -552,12 +563,15 @@ impl<A: BlockAnchor> TxGraph<A> {
|
||||
where
|
||||
C: ChainOracle,
|
||||
{
|
||||
if self.get_position_in_chain(&chain, outpoint.txid)?.is_none() {
|
||||
if self
|
||||
.try_get_chain_position(&chain, outpoint.txid)?
|
||||
.is_none()
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
if let Some(spends) = self.spends.get(&outpoint) {
|
||||
for &txid in spends {
|
||||
if let Some(observed_at) = self.get_position_in_chain(&chain, txid)? {
|
||||
if let Some(observed_at) = self.try_get_chain_position(&chain, txid)? {
|
||||
return Ok(Some((observed_at, txid)));
|
||||
}
|
||||
}
|
||||
@ -565,20 +579,12 @@ impl<A: BlockAnchor> TxGraph<A> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn transactions_in_chain<C>(
|
||||
&self,
|
||||
chain: C,
|
||||
) -> Result<BTreeSet<TxInChain<'_, Transaction, A>>, C::Error>
|
||||
pub fn get_chain_spend<C>(&self, chain: C, outpoint: OutPoint) -> Option<(ObservedIn<&A>, Txid)>
|
||||
where
|
||||
C: ChainOracle,
|
||||
C: ChainOracle<Error = Infallible>,
|
||||
{
|
||||
self.full_transactions()
|
||||
.filter_map(|tx| {
|
||||
self.get_position_in_chain(&chain, tx.txid)
|
||||
.map(|v| v.map(|observed_in| TxInChain { observed_in, tx }))
|
||||
.transpose()
|
||||
})
|
||||
.collect()
|
||||
self.try_get_spend_in_chain(chain, outpoint)
|
||||
.expect("error is infallible")
|
||||
}
|
||||
}
|
||||
|
||||
@ -802,41 +808,56 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
|
||||
self.graph.relevant_heights()
|
||||
}
|
||||
|
||||
pub fn txs_in_chain<C>(
|
||||
&self,
|
||||
pub fn try_list_chain_txs<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> Result<BTreeSet<TxInChain<'_, Transaction, A>>, C::Error>
|
||||
) -> impl Iterator<Item = Result<TxInChain<'a, Transaction, A>, C::Error>>
|
||||
where
|
||||
C: ChainOracle,
|
||||
C: ChainOracle + 'a,
|
||||
{
|
||||
let mut tx_set = self.graph.transactions_in_chain(chain)?;
|
||||
tx_set.retain(|tx| self.index.is_tx_relevant(&tx.tx));
|
||||
Ok(tx_set)
|
||||
self.graph
|
||||
.full_transactions()
|
||||
.filter(|tx| self.index.is_tx_relevant(tx))
|
||||
.filter_map(move |tx| {
|
||||
self.graph
|
||||
.try_get_chain_position(&chain, tx.txid)
|
||||
.map(|v| v.map(|observed_in| TxInChain { observed_in, tx }))
|
||||
.transpose()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn txouts_in_chain<C>(
|
||||
&self,
|
||||
pub fn list_chain_txs<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> Result<Vec<TxOutInChain<'_, I::SpkIndex, A>>, C::Error>
|
||||
) -> impl Iterator<Item = TxInChain<'a, Transaction, A>>
|
||||
where
|
||||
C: ChainOracle,
|
||||
C: ChainOracle<Error = Infallible> + 'a,
|
||||
{
|
||||
self.try_list_chain_txs(chain)
|
||||
.map(|r| r.expect("error is infallible"))
|
||||
}
|
||||
|
||||
pub fn try_list_chain_txouts<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> impl Iterator<Item = Result<TxOutInChain<'a, I::SpkIndex, A>, C::Error>>
|
||||
where
|
||||
C: ChainOracle + 'a,
|
||||
ObservedIn<A>: ChainPosition,
|
||||
{
|
||||
self.index
|
||||
.relevant_txouts()
|
||||
.iter()
|
||||
.filter_map(|(op, (spk_i, txout))| -> Option<Result<_, C::Error>> {
|
||||
self.index.relevant_txouts().iter().filter_map(
|
||||
move |(op, (spk_i, txout))| -> Option<Result<_, C::Error>> {
|
||||
let graph_tx = self.graph.get_tx(op.txid)?;
|
||||
|
||||
let is_on_coinbase = graph_tx.is_coin_base();
|
||||
|
||||
let chain_position = match self.graph.get_position_in_chain(&chain, op.txid) {
|
||||
let chain_position = match self.graph.try_get_chain_position(&chain, op.txid) {
|
||||
Ok(Some(observed_at)) => observed_at,
|
||||
Ok(None) => return None,
|
||||
Err(err) => return Some(Err(err)),
|
||||
};
|
||||
|
||||
let spent_by = match self.graph.get_spend_in_chain(&chain, *op) {
|
||||
let spent_by = match self.graph.try_get_spend_in_chain(&chain, *op) {
|
||||
Ok(spent_by) => spent_by,
|
||||
Err(err) => return Some(Err(err)),
|
||||
};
|
||||
@ -855,22 +876,45 @@ impl<A: BlockAnchor, I: TxIndex> IndexedTxGraph<A, I> {
|
||||
};
|
||||
|
||||
Some(Ok(txout_in_chain))
|
||||
})
|
||||
.collect()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn list_chain_txouts<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> impl Iterator<Item = TxOutInChain<'a, I::SpkIndex, A>>
|
||||
where
|
||||
C: ChainOracle<Error = Infallible> + 'a,
|
||||
ObservedIn<A>: ChainPosition,
|
||||
{
|
||||
self.try_list_chain_txouts(chain)
|
||||
.map(|r| r.expect("error in infallible"))
|
||||
}
|
||||
|
||||
/// Return relevant unspents.
|
||||
pub fn utxos_in_chain<C>(
|
||||
&self,
|
||||
pub fn try_list_chain_utxos<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> Result<Vec<TxOutInChain<'_, I::SpkIndex, A>>, C::Error>
|
||||
) -> impl Iterator<Item = Result<TxOutInChain<'a, I::SpkIndex, A>, C::Error>>
|
||||
where
|
||||
C: ChainOracle,
|
||||
C: ChainOracle + 'a,
|
||||
ObservedIn<A>: ChainPosition,
|
||||
{
|
||||
let mut txouts = self.txouts_in_chain(chain)?;
|
||||
txouts.retain(|txo| txo.txout.spent_by.is_none());
|
||||
Ok(txouts)
|
||||
self.try_list_chain_txouts(chain)
|
||||
.filter(|r| !matches!(r, Ok(txo) if txo.txout.spent_by.is_none()))
|
||||
}
|
||||
|
||||
pub fn list_chain_utxos<'a, C>(
|
||||
&'a self,
|
||||
chain: C,
|
||||
) -> impl Iterator<Item = TxOutInChain<'a, I::SpkIndex, A>>
|
||||
where
|
||||
C: ChainOracle<Error = Infallible> + 'a,
|
||||
ObservedIn<A>: ChainPosition,
|
||||
{
|
||||
self.try_list_chain_utxos(chain)
|
||||
.map(|r| r.expect("error is infallible"))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user