Skip to content

Commit

Permalink
fix orphan for rbf and adjust evict interval
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Oct 25, 2023
1 parent f0270ef commit ebae19a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 17 deletions.
29 changes: 14 additions & 15 deletions tx-pool/src/component/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ use ckb_types::{
packed::{OutPoint, ProposalShortId},
};
use ckb_util::shrink_to_fit;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

const SHRINK_THRESHOLD: usize = 100;
pub(crate) const ORPHAN_TX_EXPIRE_TIME: u64 = 2 * MAX_BLOCK_INTERVAL; // double block interval

/// 100 max block interval
pub(crate) const ORPHAN_TX_EXPIRE_TIME: u64 = 100 * MAX_BLOCK_INTERVAL;
pub(crate) const DEFAULT_MAX_ORPHAN_TRANSACTIONS: usize = 100;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -39,7 +41,7 @@ impl Entry {
#[derive(Default, Debug, Clone)]
pub(crate) struct OrphanPool {
pub(crate) entries: HashMap<ProposalShortId, Entry>,
pub(crate) by_out_point: HashMap<OutPoint, ProposalShortId>,
pub(crate) by_out_point: HashMap<OutPoint, HashSet<ProposalShortId>>,
}

impl OrphanPool {
Expand All @@ -60,7 +62,7 @@ impl OrphanPool {
self.entries.contains_key(id)
}

pub fn shrink_to_fit(&mut self) {
fn shrink_to_fit(&mut self) {
shrink_to_fit!(self.entries, SHRINK_THRESHOLD);
shrink_to_fit!(self.by_out_point, SHRINK_THRESHOLD);
}
Expand All @@ -73,7 +75,9 @@ impl OrphanPool {
self.entries.remove(id).map(|entry| {
debug!("remove orphan tx {}", entry.tx.hash());
for out_point in entry.tx.input_pts_iter() {
self.by_out_point.remove(&out_point);
self.by_out_point
.get_mut(&out_point)
.map(|set| set.remove(id));
}
entry
})
Expand Down Expand Up @@ -134,23 +138,17 @@ impl OrphanPool {
return vec![];
}

// double spend checking
if tx
.input_pts_iter()
.any(|out_point| self.by_out_point.contains_key(&out_point))
{
return vec![];
}

debug!("add_orphan_tx {}", tx.hash());

self.entries.insert(
tx.proposal_short_id(),
Entry::new(tx.clone(), peer, declared_cycle),
);

for out_point in tx.input_pts_iter() {
self.by_out_point.insert(out_point, tx.proposal_short_id());
self.by_out_point
.entry(out_point)
.or_insert_with(HashSet::default)
.insert(tx.proposal_short_id());
}

self.limit_size()
Expand All @@ -160,6 +158,7 @@ impl OrphanPool {
tx.output_pts()
.iter()
.filter_map(|out_point| self.by_out_point.get(out_point).cloned())
.flatten()
.collect::<Vec<_>>()
}
}
1 change: 1 addition & 0 deletions tx-pool/src/component/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod chunk;
mod entry;
mod orphan;
mod pending;
mod proposed;
mod recent_reject;
Expand Down
58 changes: 58 additions & 0 deletions tx-pool/src/component/tests/orphan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::component::orphan::OrphanPool;
use crate::component::tests::util::build_tx;
use ckb_types::packed::Byte32;

#[test]
fn test_orphan() {
let tx1 = build_tx(vec![(&Byte32::zero(), 1), (&Byte32::zero(), 2)], 1);
let mut orphan = OrphanPool::new();
assert_eq!(orphan.len(), 0);
assert!(!orphan.contains_key(&tx1.proposal_short_id()));

orphan.add_orphan_tx(tx1.clone(), 0.into(), 0);
assert_eq!(orphan.len(), 1);

orphan.add_orphan_tx(tx1.clone(), 0.into(), 0);
assert_eq!(orphan.len(), 1);

let tx2 = build_tx(vec![(&tx1.hash(), 0)], 1);
orphan.add_orphan_tx(tx2.clone(), 0.into(), 0);
assert_eq!(orphan.len(), 2);

orphan.remove_orphan_tx(&tx1.proposal_short_id());
assert_eq!(orphan.len(), 1);
orphan.remove_orphan_tx(&tx2.proposal_short_id());
assert_eq!(orphan.len(), 0);
}

#[test]
fn test_orphan_duplicated() {
let tx1 = build_tx(vec![(&Byte32::zero(), 1), (&Byte32::zero(), 2)], 3);
let mut orphan = OrphanPool::new();

let tx2 = build_tx(vec![(&tx1.hash(), 0)], 1);
let tx3 = build_tx(vec![(&tx2.hash(), 0)], 1);
let tx4 = build_tx(vec![(&tx3.hash(), 0), (&tx1.hash(), 1)], 1);
let tx5 = build_tx(vec![(&tx1.hash(), 0)], 2);
orphan.add_orphan_tx(tx1.clone(), 0.into(), 0);
orphan.add_orphan_tx(tx2.clone(), 0.into(), 0);
orphan.add_orphan_tx(tx3.clone(), 0.into(), 0);
orphan.add_orphan_tx(tx4.clone(), 0.into(), 0);
orphan.add_orphan_tx(tx5.clone(), 0.into(), 0);
assert_eq!(orphan.len(), 5);

let txs = orphan.find_by_previous(&tx2);
assert_eq!(txs.len(), 1);

let txs = orphan.find_by_previous(&tx1);
assert_eq!(txs.len(), 3);
assert!(txs.contains(&tx2.proposal_short_id()));
assert!(txs.contains(&tx4.proposal_short_id()));
assert!(txs.contains(&tx5.proposal_short_id()));

orphan.remove_orphan_tx(&tx4.proposal_short_id());
let txs = orphan.find_by_previous(&tx1);
assert_eq!(txs.len(), 2);
assert!(txs.contains(&tx2.proposal_short_id()));
assert!(txs.contains(&tx5.proposal_short_id()));
}
4 changes: 2 additions & 2 deletions tx-pool/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,14 +465,14 @@ impl TxPoolService {
peer: PeerIndex,
declared_cycle: Cycle,
) {
let evited_txs = self
let evicted_txs = self
.orphan
.write()
.await
.add_orphan_tx(tx, peer, declared_cycle);
// for any evicted orphan tx, we should send reject to relayer
// so that we mark it as `unknown` in filter
for tx_hash in evited_txs {
for tx_hash in evicted_txs {
self.send_result_to_relayer(TxVerificationResult::Reject { tx_hash });
}
}
Expand Down

0 comments on commit ebae19a

Please sign in to comment.