1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
crate::ix!();

pub trait ProcessOrphanTx {

    fn process_orphan_tx(self: Arc<Self>, orphan_work_set: &mut HashSet<u256>);
}

impl ProcessOrphanTx for PeerManager {

    /**
      | Reconsider orphan transactions after
      | a parent has been accepted to the mempool.
      | 
      | -----------
      | @param[in,out] orphan_work_set
      | 
      | The set of orphan transactions to reconsider.
      | Generally only one orphan will be reconsidered
      | on each call of this function. This set
      | may be added to if accepting an orphan
      | causes its children to be reconsidered.
      |
      */
    #[EXCLUSIVE_LOCKS_REQUIRED(CS_MAIN, G_CS_ORPHANS)]
    fn process_orphan_tx(self: Arc<Self>, orphan_work_set: &mut HashSet<u256>)  {

        assert_lock_held!(CS_MAIN);
        assert_lock_held!(G_CS_ORPHANS);

        while !orphan_work_set.is_empty() {

            let mut iter = orphan_work_set.iter().peekable();

            let orphan_hash: u256 = (*iter.peek().unwrap()).clone();

            orphan_work_set.remove(&orphan_hash);

            let (porphan_tx,from_peer) = self.orphanage.get_tx(&orphan_hash);

            let porphan_tx = self.orphanage.get_tx(&orphan_hash).0;

            if porphan_tx.is_none() {
                continue;
            }

            let result: MempoolAcceptResult = accept_to_memory_pool(
                self.chainman.get().active_chainstate(),
                self.mempool.clone(),
                porphan_tx.clone(),
                /* bypass_limits */ false,
                None
            );

            let state: &TxValidationState = &result.state;

            if result.result_type == MempoolAcceptResultType::VALID {

                log_print!(
                    LogFlags::MEMPOOL, 
                    "   accepted orphan tx %s\n", 
                    orphan_hash.to_string()
                );

                self.clone().relay_transaction(
                    &orphan_hash, 
                    porphan_tx.get().get_witness_hash()
                );

                self.orphanage.add_children_to_work_set(&porphan_tx.get(), orphan_work_set);

                self.orphanage.clone().erase_tx(&orphan_hash);

                for removed_tx in result.replaced_transactions.as_ref().unwrap().iter() {
                    self.clone().add_to_compact_extra_transactions(removed_tx);
                }

                break;

            } else {

                if state.get_result() != TxValidationResult::TX_MISSING_INPUTS {

                    if state.is_invalid() {

                        log_print!(
                            LogFlags::MEMPOOL, 
                            "   invalid orphan tx %s from peer=%d. %s\n", 
                            orphan_hash.to_string(), 
                            from_peer, 
                            state.to_string()
                        );

                        //  Maybe punish peer that gave us an invalid orphan tx
                        self.clone().maybe_punish_node_for_tx(from_peer,state,None);
                    }

                    // Has inputs but not accepted
                    // to mempool
                    //
                    // Probably non-standard or
                    // insufficient fee
                    log_print!(LogFlags::MEMPOOL,"   removed orphan tx %s\n",orphan_hash.to_string());

                    if state.get_result() != TxValidationResult::TX_WITNESS_STRIPPED {

                        //  We can add the wtxid of this transaction to our reject filter.
                        //  Do not add txids of witness transactions or witness-stripped
                        //  transactions to the filter, as they can have been malleated;
                        //  adding such txids to the reject filter would potentially
                        //  interfere with relay of valid transactions from peers that
                        //  do not support wtxid-based relay. See
                        //  https://github.com/bitcoin/bitcoin/issues/8279 for details.
                        //  We can remove this restriction (and always add wtxids to
                        //  the filter even for witness stripped transactions) once
                        //  wtxid-based relay is broadly deployed.
                        //  See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
                        //  for concerns around weakening security of unupgraded nodes
                        //  if we start doing this too early.
                        self.inner.lock().recent_rejects.insert_key(
                            porphan_tx.get().get_witness_hash().as_slice()
                        );

                        //  If the transaction
                        //  failed for
                        //  TX_INPUTS_NOT_STANDARD,
                        //  then we know that the
                        //  witness was irrelevant
                        //  to the policy failure,
                        //  since this check
                        //  depends only on the
                        //  txid (the scriptPubKey
                        //  being spent is covered
                        //  by the txid).
                        //
                        //  Add the txid to the
                        //  reject filter to
                        //  prevent repeated
                        //  processing of this
                        //  transaction in the
                        //  event that child
                        //  transactions are later
                        //  received (resulting in
                        //  parent-fetching by
                        //  txid via the
                        //  orphan-handling
                        //  logic).
                        if state.get_result() == TxValidationResult::TX_INPUTS_NOT_STANDARD 
                        && porphan_tx.get().get_witness_hash() != porphan_tx.get().get_hash() 
                        {
                            // We only add the
                            // txid if it differs
                            // from the wtxid, to
                            // avoid wasting
                            // entries in the
                            // rolling bloom
                            // filter.
                            self.inner.lock().recent_rejects.insert_key(
                                porphan_tx.get().get_hash().as_slice()
                            );
                        }
                    }

                    self.orphanage.clone().erase_tx(&orphan_hash);

                    break;
                }
            }
        }

        let chainman = self.chainman.get();

        let active_chainstate = chainman.active_chainstate();

        let chain_height = active_chainstate.height().unwrap();

        let coins_tip = active_chainstate.coins_tip();

        let active_chainstate_height_p1 = chain_height + 1;

        self.mempool.get().check(
            coins_tip, 
            active_chainstate_height_p1.try_into().unwrap() 
        );
    }
}