pub enum ObservedAs<A> {
/// The chain data is seen as confirmed, and in anchored by `A`.
Confirmed(A),
- /// The chain data is assumed to be confirmed, because a transaction that spends it is anchored
- /// by `A`.
- ConfirmedImplicit(A),
/// The chain data is seen in mempool at this given timestamp.
Unconfirmed(u64),
}
pub fn cloned(self) -> ObservedAs<A> {
match self {
ObservedAs::Confirmed(a) => ObservedAs::Confirmed(a.clone()),
- ObservedAs::ConfirmedImplicit(a) => ObservedAs::ConfirmedImplicit(a.clone()),
ObservedAs::Unconfirmed(last_seen) => ObservedAs::Unconfirmed(last_seen),
}
}
let tx_height = match &self.chain_position {
ObservedAs::Confirmed(anchor) => anchor.confirmation_height(),
- // although we do not know the exact confirm height, the returned height here is the
- // "upper bound" so only false-negatives are possible
- ObservedAs::ConfirmedImplicit(anchor) => anchor.confirmation_height(),
ObservedAs::Unconfirmed(_) => {
debug_assert!(false, "coinbase tx can never be unconfirmed");
return false;
let confirmation_height = match &self.chain_position {
ObservedAs::Confirmed(anchor) => anchor.confirmation_height(),
- // although we do not know the exact confirm height, the returned height here is the
- // "upper bound" so only false-negatives are possible
- ObservedAs::ConfirmedImplicit(anchor) => anchor.confirmation_height(),
ObservedAs::Unconfirmed(_) => return false,
};
if confirmation_height > tip {
-use core::{convert::Infallible, ops::Deref};
+use core::convert::Infallible;
use alloc::collections::{BTreeMap, BTreeSet};
use bitcoin::BlockHash;
use crate::{Append, BlockId, ChainOracle};
+/// This is a local implementation of [`ChainOracle`].
+///
+/// TODO: We need a cache/snapshot thing for chain oracle.
+/// * Minimize calls to remotes.
+/// * Can we cache it forever? Should we drop stuff?
+/// * Assume anything deeper than (i.e. 10) blocks won't be reorged.
+/// * Is this a cache on txs or block? or both?
+/// TODO: Parents of children are confirmed if children are confirmed.
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LocalChain {
blocks: BTreeMap<u32, BlockHash>,
}
-// [TODO] We need a cache/snapshot thing for chain oracle.
-// * Minimize calls to remotes.
-// * Can we cache it forever? Should we drop stuff?
-// * Assume anything deeper than (i.e. 10) blocks won't be reorged.
-// * Is this a cache on txs or block? or both?
-// [TODO] Parents of children are confirmed if children are confirmed.
impl ChainOracle for LocalChain {
type Error = Infallible;
changeset.insert(*height, *new_hash);
}
}
- Ok(ChangeSet(changeset))
+ Ok(changeset)
}
/// Applies the given `changeset`.
pub fn apply_changeset(&mut self, mut changeset: ChangeSet) {
- self.blocks.append(&mut changeset.0)
+ self.blocks.append(&mut changeset)
}
/// Updates [`LocalChain`] with an update [`LocalChain`].
}
pub fn initial_changeset(&self) -> ChangeSet {
- ChangeSet(self.blocks.clone())
+ self.blocks.clone()
}
pub fn heights(&self) -> BTreeSet<u32> {
/// This is the return value of [`determine_changeset`] and represents changes to [`LocalChain`].
///
/// [`determine_changeset`]: LocalChain::determine_changeset
-#[derive(Debug, Default, Clone, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Deserialize, serde::Serialize),
- serde(crate = "serde_crate")
-)]
-pub struct ChangeSet(pub(crate) BTreeMap<u32, BlockHash>);
-
-impl Deref for ChangeSet {
- type Target = BTreeMap<u32, BlockHash>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
+type ChangeSet = BTreeMap<u32, BlockHash>;
impl Append for ChangeSet {
fn append(&mut self, mut other: Self) {
- BTreeMap::append(&mut self.0, &mut other.0)
+ BTreeMap::append(self, &mut other)
}
}
}
}
- // If we cannot determine whether tx is in best chain, we can check whether a spending tx is
- // confirmed and in best chain, and if so, it is guaranteed that this tx is in the best
- // chain.
- //
- // [TODO] This logic is incomplete as we do not check spends of spends.
- let spending_anchors = self
- .spends
- .range(OutPoint::new(txid, u32::MIN)..=OutPoint::new(txid, u32::MAX))
- .flat_map(|(_, spending_txids)| spending_txids)
- .filter_map(|spending_txid| self.txs.get(spending_txid))
- .flat_map(|(_, spending_anchors, _)| spending_anchors);
- for spending_anchor in spending_anchors {
- match chain.is_block_in_chain(spending_anchor.anchor_block(), chain_tip)? {
- Some(true) => return Ok(Some(ObservedAs::ConfirmedImplicit(spending_anchor))),
- _ => continue,
- }
- }
-
// The tx is not anchored to a block which is in the best chain, let's check whether we can
// ignore it by checking conflicts!
let tx = match tx_node {