verbs_rs/env/
validator.rs1use alloy_primitives::{Address, U256};
4use rand::{seq::SliceRandom, Rng};
5
6use crate::contract::Transaction;
7use std::collections::HashMap;
8
9pub trait Validator {
15 fn order_transactions<R: Rng>(
26 &mut self,
27 rng: &mut R,
28 transactions: Vec<Transaction>,
29 ) -> Vec<Transaction>;
30}
31
32pub struct RandomValidator {}
34
35impl Validator for RandomValidator {
36 fn order_transactions<R: Rng>(
37 &mut self,
38 rng: &mut R,
39 mut transactions: Vec<Transaction>,
40 ) -> Vec<Transaction> {
41 transactions.as_mut_slice().shuffle(rng);
42 transactions
43 }
44}
45
46pub struct GasPriorityValidator {}
63
64impl Validator for GasPriorityValidator {
65 fn order_transactions<R: Rng>(
66 &mut self,
67 _rng: &mut R,
68 transactions: Vec<Transaction>,
69 ) -> Vec<Transaction> {
70 let mut transaction_by_address = HashMap::<Address, Vec<Transaction>>::new();
71
72 for t in transactions.into_iter() {
73 match transaction_by_address.entry(t.callee) {
74 std::collections::hash_map::Entry::Occupied(mut o) => {
75 o.get_mut().push(t);
76 }
77 std::collections::hash_map::Entry::Vacant(v) => {
78 v.insert(vec![t]);
79 }
80 };
81 }
82
83 let mut transactions: Vec<Vec<Transaction>> = transaction_by_address
84 .into_values()
85 .map(|mut v| {
86 v.sort_by_key(|x| x.nonce);
87 v
88 })
89 .collect();
90
91 transactions.sort_by_key(|x| U256::MAX - x[0].gas_priority_fee.unwrap_or(U256::ZERO));
92
93 transactions.into_iter().flatten().collect()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99
100 use super::*;
101 use alloy_primitives::{Address, Uint, U256};
102 use rand::SeedableRng;
103 use rand_xoshiro::Xoroshiro128StarStar;
104
105 #[test]
106 fn test_gas_priority() {
107 let mut rng = Xoroshiro128StarStar::seed_from_u64(101);
108
109 let address_a = Address::from(Uint::from(101u128));
110 let address_b = Address::from(Uint::from(202u128));
111
112 let transactions = vec![
113 Transaction {
114 function_selector: [0; 4],
115 callee: address_a,
116 transact_to: Address::ZERO,
117 args: Vec::default(),
118 gas_priority_fee: Some(U256::from(10)),
119 nonce: Some(1),
120 value: U256::ZERO,
121 checked: false,
122 },
123 Transaction {
124 function_selector: [0; 4],
125 callee: address_b,
126 transact_to: Address::ZERO,
127 args: Vec::default(),
128 gas_priority_fee: None,
129 nonce: Some(1),
130 value: U256::ZERO,
131 checked: false,
132 },
133 Transaction {
134 function_selector: [0; 4],
135 callee: address_a,
136 transact_to: Address::ZERO,
137 args: Vec::default(),
138 gas_priority_fee: None,
139 nonce: Some(2),
140 value: U256::ZERO,
141 checked: false,
142 },
143 Transaction {
144 function_selector: [0; 4],
145 callee: address_b,
146 transact_to: Address::ZERO,
147 args: Vec::default(),
148 gas_priority_fee: None,
149 nonce: Some(2),
150 value: U256::ZERO,
151 checked: false,
152 },
153 ];
154
155 let mut validator = GasPriorityValidator {};
156
157 let transactions = validator.order_transactions(&mut rng, transactions);
158
159 assert!(transactions.len() == 4);
160
161 assert!(transactions[0].callee == address_a);
162 assert!(transactions[0].nonce == Some(1));
163
164 assert!(transactions[1].callee == address_a);
165 assert!(transactions[1].nonce == Some(2));
166
167 assert!(transactions[2].callee == address_b);
168 assert!(transactions[2].nonce == Some(1));
169
170 assert!(transactions[3].callee == address_b);
171 assert!(transactions[3].nonce == Some(2));
172 }
173}