fuel_core_txpool/
config.rs

1use std::{
2    collections::HashSet,
3    time::Duration,
4};
5
6use fuel_core_types::{
7    fuel_tx::{
8        Address,
9        ContractId,
10        Input,
11        UtxoId,
12        input::{
13            coin::{
14                CoinPredicate,
15                CoinSigned,
16            },
17            message::{
18                MessageCoinPredicate,
19                MessageCoinSigned,
20                MessageDataPredicate,
21                MessageDataSigned,
22            },
23        },
24    },
25    fuel_types::Nonce,
26    services::txpool::PoolTransaction,
27};
28
29use crate::error::BlacklistedError;
30
31#[derive(Default, Debug, Clone, PartialEq, Eq)]
32pub struct BlackList {
33    /// Blacklisted addresses.
34    pub owners: HashSet<Address>,
35    /// Blacklisted UTXO ids.
36    pub coins: HashSet<UtxoId>,
37    /// Blacklisted messages by `Nonce`.
38    pub messages: HashSet<Nonce>,
39    /// Blacklisted contracts.
40    pub contracts: HashSet<ContractId>,
41}
42
43impl BlackList {
44    /// Create a new blacklist.
45    pub fn new(
46        owners: Vec<Address>,
47        utxo_ids: Vec<UtxoId>,
48        messages: Vec<Nonce>,
49        contracts: Vec<ContractId>,
50    ) -> Self {
51        Self {
52            owners: owners.into_iter().collect(),
53            coins: utxo_ids.into_iter().collect(),
54            messages: messages.into_iter().collect(),
55            contracts: contracts.into_iter().collect(),
56        }
57    }
58
59    /// Check if the transaction has blacklisted inputs.
60    pub fn check_blacklisting(
61        &self,
62        tx: &PoolTransaction,
63    ) -> Result<(), BlacklistedError> {
64        for input in tx.inputs() {
65            match input {
66                Input::CoinSigned(CoinSigned { utxo_id, owner, .. })
67                | Input::CoinPredicate(CoinPredicate { utxo_id, owner, .. }) => {
68                    if self.coins.contains(utxo_id) {
69                        return Err(BlacklistedError::BlacklistedUTXO(*utxo_id));
70                    }
71                    if self.owners.contains(owner) {
72                        return Err(BlacklistedError::BlacklistedOwner(*owner));
73                    }
74                }
75                Input::Contract(contract) => {
76                    if self.contracts.contains(&contract.contract_id) {
77                        return Err(BlacklistedError::BlacklistedContract(
78                            contract.contract_id,
79                        ));
80                    }
81                }
82                Input::MessageCoinSigned(MessageCoinSigned {
83                    nonce,
84                    sender,
85                    recipient,
86                    ..
87                })
88                | Input::MessageCoinPredicate(MessageCoinPredicate {
89                    nonce,
90                    sender,
91                    recipient,
92                    ..
93                })
94                | Input::MessageDataSigned(MessageDataSigned {
95                    nonce,
96                    sender,
97                    recipient,
98                    ..
99                })
100                | Input::MessageDataPredicate(MessageDataPredicate {
101                    nonce,
102                    sender,
103                    recipient,
104                    ..
105                }) => {
106                    if self.messages.contains(nonce) {
107                        return Err(BlacklistedError::BlacklistedMessage(*nonce));
108                    }
109                    if self.owners.contains(sender) {
110                        return Err(BlacklistedError::BlacklistedOwner(*sender));
111                    }
112                    if self.owners.contains(recipient) {
113                        return Err(BlacklistedError::BlacklistedOwner(*recipient));
114                    }
115                }
116            }
117        }
118
119        Ok(())
120    }
121}
122
123#[derive(Clone, Debug)]
124pub struct Config {
125    /// Enable UTXO validation (will check if UTXO exists in the database and has correct data).
126    pub utxo_validation: bool,
127    /// Allow syscalls (using ECAL). These will be ignored during txpool verifications.
128    pub allow_syscall: bool,
129    /// Maximum transactions per dependencies chain.
130    pub max_txs_chain_count: usize,
131    /// Pool limits
132    pub pool_limits: PoolLimits,
133    /// Service channel limits
134    pub service_channel_limits: ServiceChannelLimits,
135    /// Interval for checking the time to live of transactions.
136    pub ttl_check_interval: Duration,
137    /// Maximum transaction time to live.
138    pub max_txs_ttl: Duration,
139    /// Heavy async processing configuration.
140    pub heavy_work: HeavyWorkConfig,
141    /// Blacklist. Transactions with blacklisted inputs will not be accepted.
142    pub black_list: BlackList,
143    /// TTL for transactions inside the pending pool.
144    pub pending_pool_tx_ttl: Duration,
145    /// Maximum percentage of the pool size to be used for the pending pool.
146    pub max_pending_pool_size_percentage: u16,
147    /// Enable metrics when set to true
148    pub metrics: bool,
149}
150
151#[derive(Clone, Debug)]
152pub struct PoolLimits {
153    /// Maximum number of transactions in the pool.
154    pub max_txs: usize,
155    /// Maximum number of gas in the pool.
156    pub max_gas: u64,
157    /// Maximum number of bytes in the pool.
158    pub max_bytes_size: usize,
159}
160
161#[derive(Clone, Copy, Debug)]
162pub struct ServiceChannelLimits {
163    /// Maximum number of pending requests waiting in the write pool channel.
164    pub max_pending_write_pool_requests: usize,
165    /// Maximum number of pending requests waiting in the read pool channel.
166    pub max_pending_read_pool_requests: usize,
167}
168
169#[derive(Clone, Debug)]
170pub struct HeavyWorkConfig {
171    /// Maximum of threads for managing verifications/insertions.
172    pub number_threads_to_verify_transactions: usize,
173    /// Maximum of tasks in the heavy async processing queue.
174    pub size_of_verification_queue: usize,
175    /// Maximum number of threads for managing the p2p synchronisation
176    pub number_threads_p2p_sync: usize,
177    /// Maximum number of tasks in the p2p sync queue
178    pub size_of_p2p_sync_queue: usize,
179}
180
181#[cfg(feature = "test-helpers")]
182impl Default for Config {
183    fn default() -> Self {
184        Self {
185            utxo_validation: true,
186            allow_syscall: true,
187            max_txs_chain_count: 50,
188            ttl_check_interval: Duration::from_secs(60),
189            max_txs_ttl: Duration::from_secs(60 * 10),
190            black_list: BlackList::default(),
191            pool_limits: PoolLimits {
192                max_txs: 10000,
193                max_gas: 100_000_000_000,
194                max_bytes_size: 1_000_000_000,
195            },
196            heavy_work: HeavyWorkConfig {
197                // It is important for tests to have only one thread for verification
198                // because some of them rely on the ordering of insertion.
199                number_threads_to_verify_transactions: 0,
200                size_of_verification_queue: 100,
201                number_threads_p2p_sync: 0,
202                size_of_p2p_sync_queue: 100,
203            },
204            service_channel_limits: ServiceChannelLimits {
205                max_pending_write_pool_requests: 1000,
206                max_pending_read_pool_requests: 1000,
207            },
208            pending_pool_tx_ttl: Duration::from_secs(3),
209            max_pending_pool_size_percentage: 50,
210            metrics: false,
211        }
212    }
213}