1
+ use serde:: { Deserialize , Serialize } ;
2
+
1
3
use crate :: block:: {
2
4
Transaction ,
3
5
Block
4
6
} ;
7
+ use std:: cmp:: Ordering ;
5
8
pub mod rocksdb;
6
9
7
10
#[ tonic:: async_trait]
8
11
pub trait MempoolTransactionOperations {
9
12
10
- /// Checks whether a transaction exists in the mempool.
11
- async fn has_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < bool , anyhow:: Error > ;
13
+ // todo: move mempool_transaction methods into separate trait
14
+
15
+ /// Checks whether a mempool transaction exists in the mempool.
16
+ async fn has_mempool_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < bool , anyhow:: Error > ;
17
+
18
+ /// Adds a mempool transaction to the mempool.
19
+ async fn add_mempool_transaction ( & self , tx : MempoolTransaction ) -> Result < ( ) , anyhow:: Error > ;
20
+
21
+ /// Removes a mempool transaction from the mempool.
22
+ async fn remove_mempool_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < ( ) , anyhow:: Error > ;
23
+
24
+ /// Pops mempool transaction from the mempool.
25
+ async fn pop_mempool_transaction ( & self ) -> Result < Option < MempoolTransaction > , anyhow:: Error > ;
26
+
27
+ /// Gets a mempool transaction from the mempool.
28
+ async fn get_mempool_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < Option < MempoolTransaction > , anyhow:: Error > ;
29
+
30
+ /// Pops the next n mempool transactions from the mempool.
31
+ async fn pop_mempool_transactions ( & self , n : usize ) -> Result < Vec < MempoolTransaction > , anyhow:: Error > {
32
+ let mut mempool_transactions = Vec :: new ( ) ;
33
+ for _ in 0 ..n {
34
+ if let Some ( mempool_transaction) = self . pop_mempool_transaction ( ) . await ? {
35
+ mempool_transactions. push ( mempool_transaction) ;
36
+ } else {
37
+ break ;
38
+ }
39
+ }
40
+ Ok ( mempool_transactions)
41
+ }
42
+
43
+ /// Checks whether the mempool has the transaction.
44
+ async fn has_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < bool , anyhow:: Error > {
45
+ self . has_mempool_transaction ( transaction_id) . await
46
+ }
12
47
13
48
/// Adds a transaction to the mempool.
14
- async fn add_transaction ( & self , tx : Transaction ) -> Result < ( ) , anyhow:: Error > ;
49
+ async fn add_transaction ( & self , tx : Transaction ) -> Result < ( ) , anyhow:: Error > {
50
+
51
+ if self . has_transaction ( tx. id ( ) ) . await ? {
52
+ return Ok ( ( ) ) ;
53
+ }
54
+
55
+ let mempool_transaction = MempoolTransaction :: slot_now ( tx) ;
56
+ self . add_mempool_transaction ( mempool_transaction) . await
57
+
58
+ }
15
59
16
60
/// Removes a transaction from the mempool.
17
- async fn remove_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < ( ) , anyhow:: Error > ;
61
+ async fn remove_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < ( ) , anyhow:: Error > {
62
+ self . remove_mempool_transaction ( transaction_id) . await
63
+ }
18
64
19
65
/// Pops transaction from the mempool.
20
- async fn pop_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < Transaction , anyhow:: Error > ;
21
-
66
+ async fn pop_transaction ( & self ) -> Result < Option < Transaction > , anyhow:: Error > {
67
+ let mempool_transaction = self . pop_mempool_transaction ( ) . await ?;
68
+ Ok ( mempool_transaction. map ( |mempool_transaction| mempool_transaction. transaction ) )
69
+ }
70
+
22
71
/// Gets a transaction from the mempool.
23
- async fn get_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < Transaction , anyhow:: Error > ;
72
+ async fn get_transaction ( & self , transaction_id : avalanche_types:: ids:: Id ) -> Result < Option < Transaction > , anyhow:: Error > {
73
+ let mempool_transaction = self . get_mempool_transaction ( transaction_id) . await ?;
74
+ Ok ( mempool_transaction. map ( |mempool_transaction| mempool_transaction. transaction ) )
75
+ }
24
76
25
- /// Provides well-ordered transaction iterable
26
- async fn iter ( & self ) -> Result < impl Iterator < Item = Transaction > , anyhow:: Error > ;
77
+ /// Pops the next n transactions from the mempool.
78
+ async fn pop_transactions ( & self , n : usize ) -> Result < Vec < Transaction > , anyhow:: Error > {
79
+ let mempool_transactions = self . pop_mempool_transactions ( n) . await ?;
80
+ Ok ( mempool_transactions. into_iter ( ) . map ( |mempool_transaction| mempool_transaction. transaction ) . collect ( ) )
81
+ }
27
82
28
83
}
29
84
@@ -38,15 +93,91 @@ pub trait MempoolBlockOperations {
38
93
39
94
/// Removes a block from the mempool.
40
95
async fn remove_block ( & self , block_id : avalanche_types:: ids:: Id ) -> Result < ( ) , anyhow:: Error > ;
41
-
42
- /// Pops block from the mempool.
43
- async fn pop_block ( & self , block_id : avalanche_types:: ids:: Id ) -> Result < Block , anyhow:: Error > ;
44
96
45
97
/// Gets a block from the mempool.
46
- async fn get_block ( & self , block_id : avalanche_types:: ids:: Id ) -> Result < Block , anyhow:: Error > ;
98
+ async fn get_block ( & self , block_id : avalanche_types:: ids:: Id ) -> Result < Option < Block > , anyhow:: Error > ;
99
+
100
+ }
47
101
102
+ /// Wraps a transaction with a timestamp for help ordering.
103
+ #[ derive( Debug , Clone , Hash , PartialEq , Eq , Serialize , Deserialize ) ]
104
+ pub struct MempoolTransaction {
105
+ pub transaction : Transaction ,
106
+ pub timestamp : u64 ,
107
+ pub slot_seconds : u64
48
108
}
49
109
110
+ impl PartialOrd for MempoolTransaction {
111
+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
112
+ Some ( self . cmp ( other) )
113
+ }
114
+ }
115
+
116
+ /// Ordered first by slot_seconds, then by transaction.
117
+ /// This allows us to use a BTreeSet to order transactions by slot_seconds, and then by transaction and pop them off in order.
118
+ impl Ord for MempoolTransaction {
119
+ fn cmp ( & self , other : & Self ) -> Ordering {
120
+ // First, compare by slot_seconds
121
+ match self . slot_seconds . cmp ( & other. slot_seconds ) {
122
+ Ordering :: Equal => { }
123
+ non_equal => return non_equal,
124
+ }
125
+ // If slot_seconds are equal, then compare by transaction
126
+ self . transaction . cmp ( & other. transaction )
127
+ }
128
+ }
129
+
130
+ impl MempoolTransaction {
131
+
132
+ const SLOT_SECONDS : u64 = 2 ;
133
+
134
+ /// Creates a test MempoolTransaction.
135
+ pub fn test ( ) -> Self {
136
+ Self {
137
+ transaction : Transaction :: test ( ) ,
138
+ timestamp : 0 ,
139
+ slot_seconds : Self :: SLOT_SECONDS
140
+ }
141
+ }
142
+
143
+ pub fn at_time ( transaction : Transaction , timestamp : u64 ) -> Self {
144
+ let floor = (
145
+ timestamp / Self :: SLOT_SECONDS
146
+ ) * Self :: SLOT_SECONDS ;
147
+ Self {
148
+ transaction,
149
+ timestamp : floor,
150
+ slot_seconds : Self :: SLOT_SECONDS
151
+ }
152
+ }
153
+
154
+ pub fn new ( transaction : Transaction , timestamp : u64 , slot_seconds : u64 ) -> Self {
155
+ Self {
156
+ transaction,
157
+ timestamp,
158
+ slot_seconds
159
+ }
160
+ }
161
+
162
+ /// Creates a new MempoolTransaction with the current timestamp floored to the nearest slot.
163
+ /// todo: probably want to move this out to a factory.
164
+ pub fn slot_now ( transaction : Transaction ) -> MempoolTransaction {
165
+
166
+ let timestamp = std:: time:: SystemTime :: now ( ) . duration_since ( std:: time:: UNIX_EPOCH ) . unwrap ( ) . as_secs ( ) ;
167
+
168
+ Self :: at_time ( transaction, timestamp)
169
+
170
+ }
171
+
172
+ pub fn id ( & self ) -> avalanche_types:: ids:: Id {
173
+ self . transaction . id ( )
174
+ }
175
+
176
+
177
+ }
178
+
179
+
180
+ /// Combines RocksdbMempool with InMemoryMempool.
50
181
#[ derive( Debug , Clone ) ]
51
182
pub struct Mempool {
52
183
0 commit comments