cfx_packing_pool/pool_config.rs
1use cfx_math::nth_inv_root;
2use cfx_types::U256;
3use typenum::{U12, U15, U2, U3, U4, U5};
4
5use crate::transaction::PackingPoolTransaction;
6use malloc_size_of_derive::MallocSizeOf;
7
8/// Configuration settings for a [`PackingBatch`][crate::PackingBatch].
9#[derive(Default, MallocSizeOf, Clone, Copy)]
10pub struct PackingPoolConfig {
11 /// The maximum gas limit for a packing batch. If there is only a single
12 /// transaction, this limit is not enforced.
13 pub(crate) address_gas_limit: U256,
14 /// The maximum number of transactions allowed in a packing batch.
15 pub(crate) address_tx_count: usize,
16 /// The degree parameter used in the random packing algorithm, with
17 /// supported values ranging from 1 to 5.
18 pub(crate) loss_ratio_degree: u8,
19}
20
21impl PackingPoolConfig {
22 pub fn new(
23 address_gas_limit: U256, address_tx_count: usize, loss_ratio_degree: u8,
24 ) -> Self {
25 assert!(loss_ratio_degree > 0 && loss_ratio_degree <= 5);
26 Self {
27 address_gas_limit,
28 address_tx_count,
29 loss_ratio_degree,
30 }
31 }
32
33 #[cfg(test)]
34 pub fn new_for_test() -> Self { Self::new(3_000_000.into(), 20, 4) }
35
36 /// Calculates the longest acceptable prefix of transactions in the provided
37 /// list.
38 ///
39 /// This function determines the maximum number of consecutive transactions
40 /// starting from the beginning of `txs` that can be accepted based on
41 /// their cumulative gas limit and other criteria. It returns the index
42 /// of the first transaction that is not acceptable and the total gas limit
43 /// of the acceptable portion.
44 ///
45 /// # Parameters
46 /// - `txs`: A reference to a vector of transactions to be evaluated.
47 /// - `replaced`: An optional parameter that, if provided, indicates a
48 /// specific transaction and its position in `txs` that should be
49 /// considered as replaced for the purpose of this calculation. This is
50 /// used to simulate the effect of replacing a transaction within `txs`.
51 ///
52 /// # Returns
53 /// Returns a tuple containing:
54 /// - The index of the first transaction in `txs` that is not acceptable. If
55 /// all transactions are acceptable, this will be the length of `txs`.
56 /// - The total gas limit of the acceptable portion of `txs`.
57 #[inline]
58 pub(crate) fn check_acceptable_batch<TX: PackingPoolTransaction>(
59 &self, txs: &Vec<TX>, replaced: Option<(&TX, usize)>,
60 ) -> (usize, U256) {
61 let mut total_gas_limit = U256::zero();
62 for (idx, tx) in txs.iter().enumerate() {
63 if idx >= self.address_tx_count {
64 return (idx, total_gas_limit);
65 }
66
67 let tx_gas = replaced
68 .filter(|(_, i)| idx == *i)
69 .map_or(tx.gas_limit(), |(r, _)| r.gas_limit());
70
71 if total_gas_limit + tx_gas > self.address_gas_limit {
72 if idx == 0 {
73 // If there is only one tx, it can exceed address_gas_limit
74 return (1, tx_gas);
75 } else {
76 return (idx, total_gas_limit);
77 }
78 }
79 total_gas_limit += tx_gas;
80 }
81 (txs.len(), total_gas_limit)
82 }
83
84 /// Calculates the loss ratio for the random packing algorithm.
85 ///
86 /// The loss ratio is defined as the reciprocal of `gas_price` raised to the
87 /// power of the `degree` (a configuration parameter). Since this value
88 /// is less than 1, the function represents 1 as 2^128, thereby
89 /// preserving 128 binary digits of precision in the result.
90 ///
91 /// Note that the precision of the returned value is limited:
92 /// - For `degree = 5`, the precision is 12 bits.
93 /// - For other values of `degree`, the precision is 15 bits.
94 /// This limited precision is by design, as the packing pool does not
95 /// require high precision and this approach helps in saving
96 /// computational resources.
97 pub(crate) fn loss_ratio(&self, gas_price: U256) -> U256 {
98 if gas_price.is_zero() {
99 return U256::one() << 128;
100 }
101
102 (match self.loss_ratio_degree {
103 1 => U256::MAX / gas_price,
104 2 => nth_inv_root::<U2, U15>(gas_price),
105 3 => nth_inv_root::<U3, U15>(gas_price),
106 4 => nth_inv_root::<U4, U15>(gas_price),
107 5 => nth_inv_root::<U5, U12>(gas_price),
108 _ => unreachable!(),
109 }) >> 128
110 }
111}