cuprate_dandelion_tower/pool/
incoming_tx.rs

1//! Contains [`IncomingTx`] and [`IncomingTxBuilder`]
2use crate::{State, TxState};
3
4/// An incoming transaction that has gone through the preprocessing stage.
5pub struct IncomingTx<Tx, TxId, PeerId> {
6    /// The transaction.
7    pub(crate) tx: Tx,
8    /// The transaction ID.
9    pub(crate) tx_id: TxId,
10    /// The routing state of the transaction.
11    pub(crate) routing_state: TxState<PeerId>,
12}
13
14/// An [`IncomingTx`] builder.
15///
16/// The const generics here are used to restrict what methods can be called.
17///
18/// - `RS`: routing state; a `bool` for if the routing state is set
19/// - `DBS`: database state; a `bool` for if the state in the DB is set
20pub struct IncomingTxBuilder<const RS: bool, const DBS: bool, Tx, TxId, PeerId> {
21    /// The transaction.
22    tx: Tx,
23    /// The transaction ID.
24    tx_id: TxId,
25    /// The routing state of the transaction.
26    routing_state: Option<TxState<PeerId>>,
27    /// The state of this transaction in the DB.
28    state_in_db: Option<State>,
29}
30
31impl<Tx, TxId, PeerId> IncomingTxBuilder<false, false, Tx, TxId, PeerId> {
32    /// Creates a new [`IncomingTxBuilder`].
33    pub const fn new(tx: Tx, tx_id: TxId) -> Self {
34        Self {
35            tx,
36            tx_id,
37            routing_state: None,
38            state_in_db: None,
39        }
40    }
41}
42
43impl<const DBS: bool, Tx, TxId, PeerId> IncomingTxBuilder<false, DBS, Tx, TxId, PeerId> {
44    /// Adds the routing state to the builder.
45    ///
46    /// The routing state is the origin of this transaction from our perspective.
47    pub fn with_routing_state(
48        self,
49        state: TxState<PeerId>,
50    ) -> IncomingTxBuilder<true, DBS, Tx, TxId, PeerId> {
51        IncomingTxBuilder {
52            tx: self.tx,
53            tx_id: self.tx_id,
54            routing_state: Some(state),
55            state_in_db: self.state_in_db,
56        }
57    }
58}
59
60impl<const RS: bool, Tx, TxId, PeerId> IncomingTxBuilder<RS, false, Tx, TxId, PeerId> {
61    /// Adds the database state to the builder.
62    ///
63    /// If the transaction is not in the DB already then the state should be [`None`].
64    pub fn with_state_in_db(
65        self,
66        state: Option<State>,
67    ) -> IncomingTxBuilder<RS, true, Tx, TxId, PeerId> {
68        IncomingTxBuilder {
69            tx: self.tx,
70            tx_id: self.tx_id,
71            routing_state: self.routing_state,
72            state_in_db: state,
73        }
74    }
75}
76
77impl<Tx, TxId, PeerId> IncomingTxBuilder<true, true, Tx, TxId, PeerId> {
78    /// Builds the [`IncomingTx`].
79    ///
80    /// If this returns [`None`] then the transaction does not need to be given to the dandelion pool
81    /// manager.
82    pub fn build(self) -> Option<IncomingTx<Tx, TxId, PeerId>> {
83        let routing_state = self.routing_state.unwrap();
84
85        if self.state_in_db == Some(State::Fluff) {
86            return None;
87        }
88
89        Some(IncomingTx {
90            tx: self.tx,
91            tx_id: self.tx_id,
92            routing_state,
93        })
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_builder() {
103        IncomingTxBuilder::new(1, 2)
104            .with_routing_state(TxState::Stem { from: 3 })
105            .with_state_in_db(None)
106            .build();
107
108        IncomingTxBuilder::new(1, 2)
109            .with_state_in_db(None)
110            .with_routing_state(TxState::Stem { from: 3 })
111            .build();
112    }
113}