Skip to content

Commit 6a8fe4a

Browse files
committed
Add ExecuteSC test in pool.
1 parent 992573d commit 6a8fe4a

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

massa-pool/src/tests/scenario.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use super::tools::get_transaction;
44
use crate::operation_pool::tests::POOL_SETTINGS;
5+
use crate::tests::tools::create_executesc;
56
use crate::tests::tools::{self, get_transaction_with_addresses, pool_test};
67
use crate::PoolSettings;
78
use massa_models::Address;
@@ -183,6 +184,172 @@ async fn test_pool() {
183184
)
184185
.await;
185186
}
187+
188+
#[tokio::test]
189+
#[serial]
190+
async fn test_pool_with_execute_sc() {
191+
let (cfg, thread_count, operation_validity_periods, max_pool_size_per_thread): &(
192+
PoolSettings,
193+
u8,
194+
u64,
195+
u64,
196+
) = &POOL_SETTINGS;
197+
198+
pool_test(
199+
cfg,
200+
*thread_count,
201+
*operation_validity_periods,
202+
async move |mut protocol_controller, mut pool_command_sender, pool_manager| {
203+
let op_filter = |cmd| match cmd {
204+
cmd @ ProtocolCommand::PropagateOperations(_) => Some(cmd),
205+
_ => None,
206+
};
207+
// generate transactions
208+
let mut thread_tx_lists = vec![Vec::new(); *thread_count as usize];
209+
for i in 0..18 {
210+
let fee = 40 + i;
211+
let expire_period: u64 = 40 + i;
212+
let start_period = expire_period.saturating_sub(*operation_validity_periods);
213+
let (op, thread) = create_executesc(expire_period, fee, 100, 1); // Only the fee determines the rentability
214+
let id = op.verify_integrity().unwrap();
215+
216+
let mut ops = OperationHashMap::default();
217+
ops.insert(id, op.clone());
218+
219+
pool_command_sender
220+
.add_operations(ops.clone())
221+
.await
222+
.unwrap();
223+
224+
let newly_added = match protocol_controller
225+
.wait_command(250.into(), op_filter)
226+
.await
227+
{
228+
Some(ProtocolCommand::PropagateOperations(ops)) => ops,
229+
Some(_) => panic!("unexpected protocol command"),
230+
None => panic!("unexpected timeout reached"),
231+
};
232+
assert_eq!(
233+
newly_added.keys().copied().collect::<Vec<_>>(),
234+
ops.keys().copied().collect::<Vec<_>>()
235+
);
236+
237+
// duplicate
238+
pool_command_sender
239+
.add_operations(ops.clone())
240+
.await
241+
.unwrap();
242+
243+
if let Some(cmd) = protocol_controller
244+
.wait_command(250.into(), op_filter)
245+
.await
246+
{
247+
panic!("unexpected protocol command {:?}", cmd)
248+
};
249+
250+
thread_tx_lists[thread as usize].push((id, op, start_period..=expire_period));
251+
}
252+
// sort from bigger fee to smaller and truncate
253+
for lst in thread_tx_lists.iter_mut() {
254+
lst.reverse();
255+
lst.truncate(*max_pool_size_per_thread as usize);
256+
}
257+
258+
// checks ops for thread 0 and 1 and various periods
259+
for thread in 0u8..=1 {
260+
for period in 0u64..70 {
261+
let target_slot = Slot::new(period, thread);
262+
let max_count = 3;
263+
let res = pool_command_sender
264+
.get_operation_batch(
265+
target_slot,
266+
OperationHashSet::default(),
267+
max_count,
268+
10000,
269+
)
270+
.await
271+
.unwrap();
272+
assert!(res
273+
.iter()
274+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))
275+
.eq(thread_tx_lists[target_slot.thread as usize]
276+
.iter()
277+
.filter(|(_, _, r)| r.contains(&target_slot.period))
278+
.take(max_count)
279+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
280+
}
281+
}
282+
// op ending before or at period 45 should be discarded
283+
let final_period = 45u64;
284+
pool_command_sender
285+
.update_latest_final_periods(vec![final_period; *thread_count as usize])
286+
.await
287+
.unwrap();
288+
for lst in thread_tx_lists.iter_mut() {
289+
lst.retain(|(_, op, _)| op.content.expire_period > final_period);
290+
}
291+
// checks ops for thread 0 and 1 and various periods
292+
for thread in 0u8..=1 {
293+
for period in 0u64..70 {
294+
let target_slot = Slot::new(period, thread);
295+
let max_count = 4;
296+
let res = pool_command_sender
297+
.get_operation_batch(
298+
target_slot,
299+
OperationHashSet::default(),
300+
max_count,
301+
10000,
302+
)
303+
.await
304+
.unwrap();
305+
assert!(res
306+
.iter()
307+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))
308+
.eq(thread_tx_lists[target_slot.thread as usize]
309+
.iter()
310+
.filter(|(_, _, r)| r.contains(&target_slot.period))
311+
.take(max_count)
312+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
313+
}
314+
}
315+
// add transactions from protocol with a high fee but too much in the future: should be ignored
316+
{
317+
pool_command_sender
318+
.update_current_slot(Slot::new(10, 0))
319+
.await
320+
.unwrap();
321+
let fee = 1000;
322+
let expire_period: u64 = 300;
323+
let (op, thread) = get_transaction(expire_period, fee);
324+
let id = op.verify_integrity().unwrap();
325+
let mut ops = OperationHashMap::default();
326+
ops.insert(id, op);
327+
328+
pool_command_sender.add_operations(ops).await.unwrap();
329+
330+
if let Some(cmd) = protocol_controller
331+
.wait_command(250.into(), op_filter)
332+
.await
333+
{
334+
panic!("unexpected protocol command {:?}", cmd)
335+
};
336+
let res = pool_command_sender
337+
.get_operation_batch(
338+
Slot::new(expire_period - 1, thread),
339+
OperationHashSet::default(),
340+
10,
341+
10000,
342+
)
343+
.await
344+
.unwrap();
345+
assert!(res.is_empty());
346+
}
347+
(protocol_controller, pool_command_sender, pool_manager)
348+
},
349+
)
350+
.await;
351+
}
352+
186353
#[tokio::test]
187354
#[serial]
188355
async fn test_pool_with_protocol_events() {

massa-pool/src/tests/tools.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,36 @@ pub fn get_transaction_with_addresses(
108108
Address::from_public_key(&sender_pub).get_thread(2),
109109
)
110110
}
111+
112+
pub fn create_executesc(
113+
expire_period: u64,
114+
fee: u64,
115+
max_gas: u64,
116+
gas_price: u64,
117+
) -> (Operation, u8) {
118+
let priv_key = generate_random_private_key();
119+
let sender_public_key = derive_public_key(&priv_key);
120+
121+
let data = vec![42; 7];
122+
let coins = 0;
123+
124+
let op = OperationType::ExecuteSC {
125+
data,
126+
max_gas,
127+
coins: Amount::from_str(&coins.to_string()).unwrap(),
128+
gas_price: Amount::from_str(&gas_price.to_string()).unwrap(),
129+
};
130+
131+
let content = OperationContent {
132+
sender_public_key,
133+
fee: Amount::from_str(&fee.to_string()).unwrap(),
134+
expire_period,
135+
op,
136+
};
137+
let hash = Hash::compute_from(&content.to_bytes_compact().unwrap());
138+
let signature = sign(&hash, &priv_key).unwrap();
139+
(
140+
Operation { content, signature },
141+
Address::from_public_key(&sender_public_key).get_thread(2),
142+
)
143+
}

0 commit comments

Comments
 (0)