node/transaction_pool/
transaction_pool_state.rs1use ledger::{
2 scan_state::{
3 currency::{Amount, Nonce, Slot},
4 transaction_logic::valid::UserCommand,
5 },
6 transaction_pool::{Config, ValidCommandWithHash},
7 AccountId,
8};
9use mina_p2p_messages::v2::{self, TransactionHash};
10use openmina_core::{consensus::ConsensusConstants, distributed_pool::DistributedPool};
11use serde::{Deserialize, Serialize};
12use std::collections::{BTreeMap, HashMap};
13
14use super::{candidate::TransactionPoolCandidatesState, TransactionPoolAction};
15
16pub(super) type PendingId = u32;
17
18#[derive(Serialize, Deserialize, Debug)]
19pub struct TransactionPoolState {
20 pub candidates: TransactionPoolCandidatesState,
21 pub(super) dpool: DistributedPool<TransactionState, v2::TransactionHash>,
23 pub(super) pool: ledger::transaction_pool::TransactionPool,
24 pub(super) pending_actions: BTreeMap<PendingId, TransactionPoolAction>,
25 pub(super) pending_id: PendingId,
26 pub(super) best_tip_hash: Option<v2::LedgerHash>,
27 #[serde(skip)]
29 pub(super) file: Option<std::fs::File>,
30}
31
32#[derive(Serialize, Deserialize, Debug, Clone)]
33pub struct TransactionState {
34 pub time: redux::Timestamp,
35 pub hash: TransactionHash,
36}
37
38impl AsRef<TransactionHash> for TransactionState {
39 fn as_ref(&self) -> &TransactionHash {
40 &self.hash
41 }
42}
43
44impl Clone for TransactionPoolState {
45 fn clone(&self) -> Self {
46 Self {
47 candidates: self.candidates.clone(),
48 dpool: self.dpool.clone(),
49 pool: self.pool.clone(),
50 pending_actions: self.pending_actions.clone(),
51 pending_id: self.pending_id,
52 best_tip_hash: self.best_tip_hash.clone(),
53 file: None,
54 }
55 }
56}
57
58impl TransactionPoolState {
59 pub fn new(config: Config, consensus_constants: &ConsensusConstants) -> Self {
60 Self {
61 candidates: Default::default(),
62 dpool: Default::default(),
63 pool: ledger::transaction_pool::TransactionPool::new(config, consensus_constants),
64 pending_actions: Default::default(),
65 pending_id: 0,
66 best_tip_hash: None,
67 file: None,
68 }
69 }
70
71 pub fn size(&self) -> usize {
72 self.pool.size()
73 }
74
75 pub fn for_propagation_size(&self) -> usize {
76 self.dpool.len()
77 }
78
79 pub fn contains(&self, hash: &TransactionHash) -> bool {
80 self.get(hash).is_some()
81 }
82
83 pub fn get(&self, hash: &TransactionHash) -> Option<&UserCommand> {
84 self.pool.pool.get(hash).map(|v| &v.data)
85 }
86
87 pub fn transactions(&mut self, limit: usize) -> Vec<ValidCommandWithHash> {
88 self.pool.transactions(limit)
89 }
90
91 pub fn list_includable_transactions(&self, limit: usize) -> Vec<ValidCommandWithHash> {
92 self.pool.list_includable_transactions(limit)
93 }
94
95 pub fn get_all_transactions(&self) -> Vec<ValidCommandWithHash> {
96 self.pool.get_all_transactions()
97 }
98
99 pub fn get_pending_amount_and_nonce(&self) -> HashMap<AccountId, (Option<Nonce>, Amount)> {
100 self.pool.get_pending_amount_and_nonce()
101 }
102
103 fn next_pending_id(&mut self) -> PendingId {
104 let id = self.pending_id;
105 self.pending_id = self.pending_id.wrapping_add(1);
106 id
107 }
108
109 pub(super) fn make_action_pending(&mut self, action: &TransactionPoolAction) -> PendingId {
110 let id = self.next_pending_id();
111 self.pending_actions.insert(id, action.clone());
112 id
113 }
114
115 #[allow(dead_code)]
116 fn save_actions(state: &mut crate::Substate<Self>) {
117 let substate = state.get_substate_mut().unwrap();
118 if substate.file.is_none() {
119 let mut file = std::fs::File::create("/tmp/pool.bin").unwrap();
120 postcard::to_io(&state.unsafe_get_state(), &mut file).unwrap();
121 let substate = state.get_substate_mut().unwrap();
122 substate.file = Some(file);
123 }
124 }
125
126 pub(super) fn global_slots(state: &crate::State) -> Option<(Slot, Slot)> {
127 Some((
128 Slot::from_u32(state.cur_global_slot()?),
129 Slot::from_u32(state.cur_global_slot_since_genesis()?),
130 ))
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::{super::TransactionPoolActionWithMeta, *};
137 use crate::State;
138 use redux::Dispatcher;
139
140 #[allow(unused)]
141 #[test]
142 fn test_replay_pool() {
143 let vec = std::fs::read("/tmp/pool.bin").unwrap();
144 let slice = vec.as_slice();
145
146 let (mut state, rest) = postcard::take_from_bytes::<State>(slice).unwrap();
147 let mut slice = rest;
148
149 while let Ok((action, rest)) =
150 postcard::take_from_bytes::<TransactionPoolActionWithMeta>(slice)
151 {
152 slice = rest;
153
154 let mut dispatcher = Dispatcher::new();
155 let state = crate::Substate::<TransactionPoolState>::new(&mut state, &mut dispatcher);
156 let (action, meta) = action.split();
157
158 TransactionPoolState::handle_action(state, meta.with_action(&action));
159 }
160 }
161}