chore(chain)!: rm missing_heights
and missing_heights_from
methods
These methods are no longer needed as we can determine missing heights directly from the `CheckPoint` tip.
This commit is contained in:
parent
bd62aa0fe1
commit
886d72e3d5
@ -89,8 +89,8 @@
|
|||||||
//! [`insert_txout`]: TxGraph::insert_txout
|
//! [`insert_txout`]: TxGraph::insert_txout
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collections::*, keychain::Balance, local_chain::LocalChain, Anchor, Append, BlockId,
|
collections::*, keychain::Balance, Anchor, Append, BlockId, ChainOracle, ChainPosition,
|
||||||
ChainOracle, ChainPosition, FullTxOut,
|
FullTxOut,
|
||||||
};
|
};
|
||||||
use alloc::collections::vec_deque::VecDeque;
|
use alloc::collections::vec_deque::VecDeque;
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
@ -759,69 +759,6 @@ impl<A: Clone + Ord> TxGraph<A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Anchor> TxGraph<A> {
|
impl<A: Anchor> TxGraph<A> {
|
||||||
/// Find missing block heights of `chain`.
|
|
||||||
///
|
|
||||||
/// This works by scanning through anchors, and seeing whether the anchor block of the anchor
|
|
||||||
/// exists in the [`LocalChain`]. The returned iterator does not output duplicate heights.
|
|
||||||
pub fn missing_heights<'a>(&'a self, chain: &'a LocalChain) -> impl Iterator<Item = u32> + 'a {
|
|
||||||
// Map of txids to skip.
|
|
||||||
//
|
|
||||||
// Usually, if a height of a tx anchor is missing from the chain, we would want to return
|
|
||||||
// this height in the iterator. The exception is when the tx is confirmed in chain. All the
|
|
||||||
// other missing-height anchors of this tx can be skipped.
|
|
||||||
//
|
|
||||||
// * Some(true) => skip all anchors of this txid
|
|
||||||
// * Some(false) => do not skip anchors of this txid
|
|
||||||
// * None => we do not know whether we can skip this txid
|
|
||||||
let mut txids_to_skip = HashMap::<Txid, bool>::new();
|
|
||||||
|
|
||||||
// Keeps track of the last height emitted so we don't double up.
|
|
||||||
let mut last_height_emitted = Option::<u32>::None;
|
|
||||||
|
|
||||||
self.anchors
|
|
||||||
.iter()
|
|
||||||
.filter(move |(_, txid)| {
|
|
||||||
let skip = *txids_to_skip.entry(*txid).or_insert_with(|| {
|
|
||||||
let tx_anchors = match self.txs.get(txid) {
|
|
||||||
Some((_, anchors, _)) => anchors,
|
|
||||||
None => return true,
|
|
||||||
};
|
|
||||||
let mut has_missing_height = false;
|
|
||||||
for anchor_block in tx_anchors.iter().map(Anchor::anchor_block) {
|
|
||||||
match chain.get(anchor_block.height) {
|
|
||||||
None => {
|
|
||||||
has_missing_height = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Some(chain_cp) => {
|
|
||||||
if chain_cp.hash() == anchor_block.hash {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
!has_missing_height
|
|
||||||
});
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
debug_assert!({
|
|
||||||
println!("txid={} skip={}", txid, skip);
|
|
||||||
true
|
|
||||||
});
|
|
||||||
!skip
|
|
||||||
})
|
|
||||||
.filter_map(move |(a, _)| {
|
|
||||||
let anchor_block = a.anchor_block();
|
|
||||||
if Some(anchor_block.height) != last_height_emitted
|
|
||||||
&& chain.get(anchor_block.height).is_none()
|
|
||||||
{
|
|
||||||
last_height_emitted = Some(anchor_block.height);
|
|
||||||
Some(anchor_block.height)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the position of the transaction in `chain` with tip `chain_tip`.
|
/// Get the position of the transaction in `chain` with tip `chain_tip`.
|
||||||
///
|
///
|
||||||
/// Chain data is fetched from `chain`, a [`ChainOracle`] implementation.
|
/// Chain data is fetched from `chain`, a [`ChainOracle`] implementation.
|
||||||
@ -1330,8 +1267,6 @@ impl<A> ChangeSet<A> {
|
|||||||
///
|
///
|
||||||
/// This is useful if you want to find which heights you need to fetch data about in order to
|
/// This is useful if you want to find which heights you need to fetch data about in order to
|
||||||
/// confirm or exclude these anchors.
|
/// confirm or exclude these anchors.
|
||||||
///
|
|
||||||
/// See also: [`TxGraph::missing_heights`]
|
|
||||||
pub fn anchor_heights(&self) -> impl Iterator<Item = u32> + '_
|
pub fn anchor_heights(&self) -> impl Iterator<Item = u32> + '_
|
||||||
where
|
where
|
||||||
A: Anchor,
|
A: Anchor,
|
||||||
@ -1346,24 +1281,6 @@ impl<A> ChangeSet<A> {
|
|||||||
!duplicate
|
!duplicate
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator for the [`anchor_heights`] in this changeset that are not included in
|
|
||||||
/// `local_chain`. This tells you which heights you need to include in `local_chain` in order
|
|
||||||
/// for it to conclusively act as a [`ChainOracle`] for the transaction anchors this changeset
|
|
||||||
/// will add.
|
|
||||||
///
|
|
||||||
/// [`ChainOracle`]: crate::ChainOracle
|
|
||||||
/// [`anchor_heights`]: Self::anchor_heights
|
|
||||||
pub fn missing_heights_from<'a>(
|
|
||||||
&'a self,
|
|
||||||
local_chain: &'a LocalChain,
|
|
||||||
) -> impl Iterator<Item = u32> + 'a
|
|
||||||
where
|
|
||||||
A: Anchor,
|
|
||||||
{
|
|
||||||
self.anchor_heights()
|
|
||||||
.filter(move |&height| local_chain.get(height).is_none())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Ord> Append for ChangeSet<A> {
|
impl<A: Ord> Append for ChangeSet<A> {
|
||||||
|
@ -1087,139 +1087,6 @@ fn update_last_seen_unconfirmed() {
|
|||||||
assert_eq!(graph.full_txs().next().unwrap().last_seen_unconfirmed, 2);
|
assert_eq!(graph.full_txs().next().unwrap().last_seen_unconfirmed, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_missing_blocks() {
|
|
||||||
/// An anchor implementation for testing, made up of `(the_anchor_block, random_data)`.
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, core::hash::Hash)]
|
|
||||||
struct TestAnchor(BlockId);
|
|
||||||
|
|
||||||
impl Anchor for TestAnchor {
|
|
||||||
fn anchor_block(&self) -> BlockId {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Scenario<'a> {
|
|
||||||
name: &'a str,
|
|
||||||
graph: TxGraph<TestAnchor>,
|
|
||||||
chain: LocalChain,
|
|
||||||
exp_heights: &'a [u32],
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn new_anchor(height: u32, hash: BlockHash) -> TestAnchor {
|
|
||||||
TestAnchor(BlockId { height, hash })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_scenario<'a>(
|
|
||||||
name: &'a str,
|
|
||||||
graph_anchors: &'a [(Txid, TestAnchor)],
|
|
||||||
chain: &'a [(u32, BlockHash)],
|
|
||||||
exp_heights: &'a [u32],
|
|
||||||
) -> Scenario<'a> {
|
|
||||||
Scenario {
|
|
||||||
name,
|
|
||||||
graph: {
|
|
||||||
let mut g = TxGraph::default();
|
|
||||||
for (txid, anchor) in graph_anchors {
|
|
||||||
let _ = g.insert_anchor(*txid, anchor.clone());
|
|
||||||
}
|
|
||||||
g
|
|
||||||
},
|
|
||||||
chain: {
|
|
||||||
let (mut c, _) = LocalChain::from_genesis_hash(h!("genesis"));
|
|
||||||
for (height, hash) in chain {
|
|
||||||
let _ = c.insert_block(BlockId {
|
|
||||||
height: *height,
|
|
||||||
hash: *hash,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
c
|
|
||||||
},
|
|
||||||
exp_heights,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(scenarios: &[Scenario]) {
|
|
||||||
for scenario in scenarios {
|
|
||||||
let Scenario {
|
|
||||||
name,
|
|
||||||
graph,
|
|
||||||
chain,
|
|
||||||
exp_heights,
|
|
||||||
} = scenario;
|
|
||||||
|
|
||||||
let heights = graph.missing_heights(chain).collect::<Vec<_>>();
|
|
||||||
assert_eq!(&heights, exp_heights, "scenario: {}", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run(&[
|
|
||||||
new_scenario(
|
|
||||||
"2 txs with the same anchor (2:B) which is missing from chain",
|
|
||||||
&[
|
|
||||||
(h!("tx_1"), new_anchor(2, h!("B"))),
|
|
||||||
(h!("tx_2"), new_anchor(2, h!("B"))),
|
|
||||||
],
|
|
||||||
&[(1, h!("A")), (3, h!("C"))],
|
|
||||||
&[2],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"2 txs with different anchors at the same height, one of the anchors is missing",
|
|
||||||
&[
|
|
||||||
(h!("tx_1"), new_anchor(2, h!("B1"))),
|
|
||||||
(h!("tx_2"), new_anchor(2, h!("B2"))),
|
|
||||||
],
|
|
||||||
&[(1, h!("A")), (2, h!("B1"))],
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"tx with 2 anchors of same height which are missing from the chain",
|
|
||||||
&[
|
|
||||||
(h!("tx"), new_anchor(3, h!("C1"))),
|
|
||||||
(h!("tx"), new_anchor(3, h!("C2"))),
|
|
||||||
],
|
|
||||||
&[(1, h!("A")), (4, h!("D"))],
|
|
||||||
&[3],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"tx with 2 anchors at the same height, chain has this height but does not match either anchor",
|
|
||||||
&[
|
|
||||||
(h!("tx"), new_anchor(4, h!("D1"))),
|
|
||||||
(h!("tx"), new_anchor(4, h!("D2"))),
|
|
||||||
],
|
|
||||||
&[(4, h!("D3")), (5, h!("E"))],
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"tx with 2 anchors at different heights, one anchor exists in chain, should return nothing",
|
|
||||||
&[
|
|
||||||
(h!("tx"), new_anchor(3, h!("C"))),
|
|
||||||
(h!("tx"), new_anchor(4, h!("D"))),
|
|
||||||
],
|
|
||||||
&[(4, h!("D")), (5, h!("E"))],
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"tx with 2 anchors at different heights, first height is already in chain with different hash, iterator should only return 2nd height",
|
|
||||||
&[
|
|
||||||
(h!("tx"), new_anchor(5, h!("E1"))),
|
|
||||||
(h!("tx"), new_anchor(6, h!("F1"))),
|
|
||||||
],
|
|
||||||
&[(4, h!("D")), (5, h!("E")), (7, h!("G"))],
|
|
||||||
&[6],
|
|
||||||
),
|
|
||||||
new_scenario(
|
|
||||||
"tx with 2 anchors at different heights, neither height is in chain, both heights should be returned",
|
|
||||||
&[
|
|
||||||
(h!("tx"), new_anchor(3, h!("C"))),
|
|
||||||
(h!("tx"), new_anchor(4, h!("D"))),
|
|
||||||
],
|
|
||||||
&[(1, h!("A")), (2, h!("B"))],
|
|
||||||
&[3, 4],
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// The `map_anchors` allow a caller to pass a function to reconstruct the [`TxGraph`] with any [`Anchor`],
|
/// The `map_anchors` allow a caller to pass a function to reconstruct the [`TxGraph`] with any [`Anchor`],
|
||||||
/// even though the function is non-deterministic.
|
/// even though the function is non-deterministic.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user