loom_types_blockchain/
mempool.rs

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
use crate::{AccountNonceAndTransactions, FetchState, GethStateUpdate, MempoolTx};
use alloy_consensus::Transaction as TransactionTrait;
use alloy_primitives::{Address, BlockNumber, TxHash};
use alloy_provider::network::TransactionResponse;
use alloy_rpc_types_eth::{Log, Transaction};
use chrono::{DateTime, Utc};
use eyre::{eyre, Result};
use std::collections::hash_map::Entry;
use std::collections::HashMap;

#[derive(Clone, Debug, Default)]
pub struct Mempool {
    pub txs: HashMap<TxHash, MempoolTx>,
    accounts: HashMap<Address, AccountNonceAndTransactions>,
}

impl Mempool {
    pub fn new() -> Mempool {
        Mempool { txs: HashMap::new(), accounts: HashMap::new() }
    }

    pub fn len(&self) -> usize {
        self.txs.len()
    }

    pub fn is_empty(&self) -> bool {
        self.txs.is_empty()
    }

    pub fn is_tx(&self, tx_hash: &TxHash) -> bool {
        self.txs.contains_key(tx_hash)
    }

    pub fn add_tx(&mut self, tx: Transaction) -> &mut Self {
        let tx_hash: TxHash = tx.tx_hash();
        let entry = self.txs.entry(tx_hash).or_default();
        entry.tx = Some(tx);
        self
    }

    pub fn add_tx_logs(&mut self, tx_hash: TxHash, logs: Vec<Log>) -> &mut Self {
        let entry = self.txs.entry(tx_hash).or_default();
        entry.logs = Some(logs);
        self
    }

    pub fn add_tx_state_change(&mut self, tx_hash: TxHash, state_update: GethStateUpdate) -> &mut Self {
        let entry = self.txs.entry(tx_hash).or_default();
        entry.state_update = Some(state_update);
        self
    }

    pub fn filter_by_gas_price(&self, gas_price: u128) -> Vec<&MempoolTx> {
        self.txs
            .values()
            .filter(|&item| {
                item.mined.is_none() && item.tx.clone().map_or_else(|| false, |i| TransactionTrait::max_fee_per_gas(&i) >= gas_price)
            })
            .collect()
    }

    pub fn filter_ok_by_gas_price(&self, gas_price: u128) -> Vec<&MempoolTx> {
        self.txs
            .values()
            .filter(|&item| {
                item.mined.is_none()
                    && !item.failed.unwrap_or(false)
                    && item.tx.clone().map_or_else(|| false, |i| TransactionTrait::max_fee_per_gas(&i) >= gas_price)
            })
            .collect()
    }

    pub fn filter_on_block(&self, block_number: BlockNumber) -> Vec<&MempoolTx> {
        self.txs.values().filter(|&item| item.mined == Some(block_number)).collect()
    }

    pub fn is_mined(&self, tx_hash: &TxHash) -> bool {
        match self.txs.get(tx_hash) {
            Some(tx) => tx.mined.is_some(),
            None => false,
        }
    }

    pub fn is_failed(&self, tx_hash: &TxHash) -> bool {
        match self.txs.get(tx_hash) {
            Some(e) => e.failed.unwrap_or(false),
            None => false,
        }
    }

    pub fn clean(&mut self) {
        self.txs = Default::default();
        self.accounts = Default::default();
    }

    pub fn clean_txs(&mut self, max_block_number: BlockNumber, max_time: DateTime<Utc>) {
        self.txs = self
            .txs
            .clone()
            .into_iter()
            .filter(|(_, v)| v.mined.unwrap_or(max_block_number + 1) > max_block_number && v.time > max_time)
            .collect();
    }

    pub fn set_mined(&mut self, tx_hash: TxHash, block_number: BlockNumber) -> &mut Self {
        let entry = self.txs.entry(tx_hash).or_default();
        entry.mined = Some(block_number);
        self
    }

    pub fn set_failed(&mut self, tx_hash: TxHash) {
        if let Entry::Occupied(mut e) = self.txs.entry(tx_hash) {
            let value = e.get_mut();
            value.failed = Some(true)
        }
    }

    pub fn set_nonce(&mut self, account: Address, nonce: u64) -> &mut Self {
        let entry = self.accounts.entry(account).or_default();
        entry.set_nonce(Some(nonce));
        self
    }

    pub fn is_valid_tx(&self, tx: &Transaction) -> bool {
        self.accounts.get(&tx.from).map_or_else(|| true, |acc| acc.nonce.map_or_else(|| true, |nonce| tx.nonce() == nonce + 1))
    }

    pub fn get_tx_by_hash(&self, tx_hash: &TxHash) -> Option<&MempoolTx> {
        self.txs.get(tx_hash)
    }

    pub fn get_or_fetch_pre_state(&mut self, _tx_hash: &TxHash) -> Result<FetchState<GethStateUpdate>> {
        Err(eyre!("NOT_IMPLEMENTED"))
    }

    pub fn remove_tx(&mut self, tx_hash: &TxHash) -> Option<MempoolTx> {
        self.txs.remove(tx_hash)
    }
}