Skip to content

Commit 4d4186e

Browse files
committed
fix: handle stale parents during ancestor eviction
1 parent 946c655 commit 4d4186e

2 files changed

Lines changed: 81 additions & 23 deletions

File tree

tx-pool/src/component/pool_map.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -600,31 +600,37 @@ impl PoolMap {
600600
return Ok(evicted);
601601
}
602602

603-
if ancestors_count.saturating_sub(cell_ref_parents.len()) <= self.max_ancestors_count {
604-
// if ancestors count exceed limitation,
605-
// try to evict some conflicted transactions due to ref cells
606-
607-
// sort them to find out the transactions with lowest fees
608-
let evict_candidates: Vec<ProposalShortId> = self
609-
.entries
610-
.iter_by_evict_key()
611-
.filter(move |entry| cell_ref_parents.contains(&entry.id))
612-
.map(|x| x.id.clone())
613-
.collect();
614-
615-
let mut iter = evict_candidates.iter();
616-
while ancestors_count > self.max_ancestors_count {
617-
if let Some(next_id) = iter.next() {
618-
let removed = self.remove_entry_and_descendants(next_id);
619-
ancestors_count = ancestors_count.saturating_sub(1);
620-
parents.remove(next_id);
621-
evicted.extend(removed);
622-
} else {
623-
break;
603+
if ancestors_count.saturating_sub(cell_ref_parents.len()) > self.max_ancestors_count {
604+
return Err(Reject::ExceededMaximumAncestorsCount);
605+
}
606+
607+
// if ancestors count exceed limitation,
608+
// try to evict some conflicted transactions due to ref cells
609+
610+
// sort them to find out the transactions with lowest fees
611+
let evict_candidates: Vec<ProposalShortId> = self
612+
.entries
613+
.iter_by_evict_key()
614+
.filter(move |entry| cell_ref_parents.contains(&entry.id))
615+
.map(|x| x.id.clone())
616+
.collect();
617+
618+
let mut iter = evict_candidates.iter();
619+
while ancestors_count > self.max_ancestors_count {
620+
if let Some(next_id) = iter.next() {
621+
let removed = self.remove_entry_and_descendants(next_id);
622+
for removed_id in removed.iter().map(|entry| entry.proposal_short_id()) {
623+
parents.remove(&removed_id);
624624
}
625+
ancestors_count = self
626+
.links
627+
.calc_relation_ids(parents.clone(), Relation::Parents)
628+
.len()
629+
+ 1;
630+
evicted.extend(removed);
631+
} else {
632+
break;
625633
}
626-
} else {
627-
return Err(Reject::ExceededMaximumAncestorsCount);
628634
}
629635

630636
// some txs in `parents` are removed, now `ancestors` need to re-caculate,

tx-pool/src/component/tests/proposed.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,58 @@ fn test_max_ancestors_with_dep() {
695695
assert_eq!(pool.edges.inputs_len(), 1);
696696
}
697697

698+
#[test]
699+
fn test_max_ancestors_evicts_stale_parent_descendant() {
700+
let mut pool = PoolMap::new(2);
701+
let dep_hash: Byte32 = h256!("0x1").into();
702+
703+
let tx1 = build_tx_with_dep(vec![(&Byte32::zero(), 0)], vec![(&dep_hash, 0)], 1);
704+
let tx1_id = tx1.proposal_short_id();
705+
let tx1_hash = tx1.hash();
706+
707+
let tx2 = build_tx(vec![(&tx1_hash, 0)], 1);
708+
let tx2_id = tx2.proposal_short_id();
709+
let tx2_hash = tx2.hash();
710+
711+
let tx3 = build_tx(vec![(&dep_hash, 0), (&tx2_hash, 0)], 1);
712+
let tx3_id = tx3.proposal_short_id();
713+
714+
pool.add_proposed(TxEntry::new(
715+
dummy_resolve(tx1, |_| None),
716+
MOCK_CYCLES,
717+
MOCK_FEE,
718+
MOCK_SIZE,
719+
))
720+
.unwrap();
721+
pool.add_proposed(TxEntry::dummy_resolve(
722+
tx2,
723+
MOCK_CYCLES,
724+
MOCK_FEE,
725+
MOCK_SIZE,
726+
))
727+
.unwrap();
728+
729+
let (inserted, evicted) = pool
730+
.add_entry(
731+
TxEntry::dummy_resolve(tx3, MOCK_CYCLES, MOCK_FEE, MOCK_SIZE),
732+
Status::Proposed,
733+
)
734+
.unwrap();
735+
assert!(inserted);
736+
737+
let evicted_ids: HashSet<_> = evicted
738+
.iter()
739+
.map(|entry| entry.proposal_short_id())
740+
.collect();
741+
assert_eq!(evicted_ids.len(), 2);
742+
assert!(evicted_ids.contains(&tx1_id));
743+
assert!(evicted_ids.contains(&tx2_id));
744+
assert!(pool.get(&tx1_id).is_none());
745+
assert!(pool.get(&tx2_id).is_none());
746+
assert!(pool.get(&tx3_id).is_some());
747+
assert!(pool.calc_ancestors(&tx3_id).is_empty());
748+
}
749+
698750
#[test]
699751
fn test_container_bench_add_limits() {
700752
use rand::Rng;

0 commit comments

Comments
 (0)