Skip to content

Commit 04600cd

Browse files
Merge #2144
2144: Add ExecuteSC test in pool. r=AureliaDolo a=AureliaDolo Fix #2076 Co-authored-by: Aurelia <adolo@massa.network>
2 parents 55027fc + 3fba31a commit 04600cd

File tree

3 files changed

+213
-10
lines changed

3 files changed

+213
-10
lines changed

massa-pool/src/operation_pool.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ pub mod tests {
466466
let mut pool =
467467
OperationPool::new(pool_settings, *thread_count, *operation_validity_periods);
468468

469-
// generate transactions
469+
// generate (id, transactions, range of validity) by threads
470470
let mut thread_tx_lists = vec![Vec::new(); *thread_count as usize];
471471
for i in 0..18 {
472472
let fee = 40 + i;
@@ -494,7 +494,7 @@ pub mod tests {
494494
lst.truncate(*max_pool_size_per_thread as usize);
495495
}
496496

497-
// checks ops for thread 0 and 1 and various periods
497+
// checks ops are the expected ones for thread 0 and 1 and various periods
498498
for thread in 0u8..=1 {
499499
for period in 0u64..70 {
500500
let target_slot = Slot::new(period, thread);
@@ -513,15 +513,16 @@ pub mod tests {
513513
}
514514
}
515515

516-
// op ending before or at period 45 should be discarded
516+
// op ending before or at period 45 won't appear in the block due to incompatible validity range
517+
// we don't keep them as expected ops
517518
let final_period = 45u64;
518519
pool.update_latest_final_periods(vec![final_period; *thread_count as usize])
519520
.unwrap();
520521
for lst in thread_tx_lists.iter_mut() {
521522
lst.retain(|(_, op, _)| op.content.expire_period > final_period);
522523
}
523524

524-
// checks ops for thread 0 and 1 and various periods
525+
// checks ops are the expected ones for thread 0 and 1 and various periods
525526
for thread in 0u8..=1 {
526527
for period in 0u64..70 {
527528
let target_slot = Slot::new(period, thread);

massa-pool/src/tests/scenario.rs

Lines changed: 175 additions & 6 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;
@@ -38,7 +39,7 @@ async fn test_pool() {
3839
cmd @ ProtocolCommand::PropagateOperations(_) => Some(cmd),
3940
_ => None,
4041
};
41-
// generate transactions
42+
// generate (id, transactions, range of validity) by threads
4243
let mut thread_tx_lists = vec![Vec::new(); *thread_count as usize];
4344
for i in 0..18 {
4445
let fee = 40 + i;
@@ -89,7 +90,7 @@ async fn test_pool() {
8990
lst.truncate(*max_pool_size_per_thread as usize);
9091
}
9192

92-
// checks ops for thread 0 and 1 and various periods
93+
// checks ops are the expected ones for thread 0 and 1 and various periods
9394
for thread in 0u8..=1 {
9495
for period in 0u64..70 {
9596
let target_slot = Slot::new(period, thread);
@@ -113,7 +114,8 @@ async fn test_pool() {
113114
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
114115
}
115116
}
116-
// op ending before or at period 45 should be discarded
117+
// op ending before or at period 45 won't appear in the block due to incompatible validity range
118+
// we don't keep them as expected ops
117119
let final_period = 45u64;
118120
pool_command_sender
119121
.update_latest_final_periods(vec![final_period; *thread_count as usize])
@@ -122,7 +124,7 @@ async fn test_pool() {
122124
for lst in thread_tx_lists.iter_mut() {
123125
lst.retain(|(_, op, _)| op.content.expire_period > final_period);
124126
}
125-
// checks ops for thread 0 and 1 and various periods
127+
// checks ops are the expected ones for thread 0 and 1 and various periods
126128
for thread in 0u8..=1 {
127129
for period in 0u64..70 {
128130
let target_slot = Slot::new(period, thread);
@@ -146,7 +148,7 @@ async fn test_pool() {
146148
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
147149
}
148150
}
149-
// add transactions from protocol with a high fee but too much in the future: should be ignored
151+
// Add transactions that should be ignored despite their high fees, due to them being too far in the future
150152
{
151153
pool_command_sender
152154
.update_current_slot(Slot::new(10, 0))
@@ -183,6 +185,173 @@ async fn test_pool() {
183185
)
184186
.await;
185187
}
188+
189+
#[tokio::test]
190+
#[serial]
191+
async fn test_pool_with_execute_sc() {
192+
let (cfg, thread_count, operation_validity_periods, max_pool_size_per_thread): &(
193+
PoolSettings,
194+
u8,
195+
u64,
196+
u64,
197+
) = &POOL_SETTINGS;
198+
199+
pool_test(
200+
cfg,
201+
*thread_count,
202+
*operation_validity_periods,
203+
async move |mut protocol_controller, mut pool_command_sender, pool_manager| {
204+
let op_filter = |cmd| match cmd {
205+
cmd @ ProtocolCommand::PropagateOperations(_) => Some(cmd),
206+
_ => None,
207+
};
208+
// generate (id, transactions, range of validity) by threads
209+
let mut thread_tx_lists = vec![Vec::new(); *thread_count as usize];
210+
for i in 0..18 {
211+
let fee = 40 + i;
212+
let expire_period: u64 = 40 + i;
213+
let start_period = expire_period.saturating_sub(*operation_validity_periods);
214+
let (op, thread) = create_executesc(expire_period, fee, 100, 1); // Only the fee determines the rentability
215+
let id = op.verify_integrity().unwrap();
216+
217+
let mut ops = OperationHashMap::default();
218+
ops.insert(id, op.clone());
219+
220+
pool_command_sender
221+
.add_operations(ops.clone())
222+
.await
223+
.unwrap();
224+
225+
let newly_added = match protocol_controller
226+
.wait_command(250.into(), op_filter)
227+
.await
228+
{
229+
Some(ProtocolCommand::PropagateOperations(ops)) => ops,
230+
Some(_) => panic!("unexpected protocol command"),
231+
None => panic!("unexpected timeout reached"),
232+
};
233+
assert_eq!(
234+
newly_added.keys().copied().collect::<Vec<_>>(),
235+
ops.keys().copied().collect::<Vec<_>>()
236+
);
237+
238+
// duplicate
239+
pool_command_sender
240+
.add_operations(ops.clone())
241+
.await
242+
.unwrap();
243+
244+
if let Some(cmd) = protocol_controller
245+
.wait_command(250.into(), op_filter)
246+
.await
247+
{
248+
panic!("unexpected protocol command {:?}", cmd)
249+
};
250+
251+
thread_tx_lists[thread as usize].push((id, op, start_period..=expire_period));
252+
}
253+
// sort from bigger fee to smaller and truncate
254+
for lst in thread_tx_lists.iter_mut() {
255+
lst.reverse();
256+
lst.truncate(*max_pool_size_per_thread as usize);
257+
}
258+
259+
// checks ops are the expected ones for thread 0 and 1 and various periods
260+
for thread in 0u8..=1 {
261+
for period in 0u64..70 {
262+
let target_slot = Slot::new(period, thread);
263+
let max_count = 3;
264+
let res = pool_command_sender
265+
.get_operation_batch(
266+
target_slot,
267+
OperationHashSet::default(),
268+
max_count,
269+
10000,
270+
)
271+
.await
272+
.unwrap();
273+
assert!(res
274+
.iter()
275+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))
276+
.eq(thread_tx_lists[target_slot.thread as usize]
277+
.iter()
278+
.filter(|(_, _, r)| r.contains(&target_slot.period))
279+
.take(max_count)
280+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
281+
}
282+
}
283+
// op ending before or at period 45 won't appear in the block due to incompatible validity range
284+
// we don't keep them as expected ops
285+
let final_period = 45u64;
286+
pool_command_sender
287+
.update_latest_final_periods(vec![final_period; *thread_count as usize])
288+
.await
289+
.unwrap();
290+
for lst in thread_tx_lists.iter_mut() {
291+
lst.retain(|(_, op, _)| op.content.expire_period > final_period);
292+
}
293+
// checks ops are the expected ones for thread 0 and 1 and various periods
294+
for thread in 0u8..=1 {
295+
for period in 0u64..70 {
296+
let target_slot = Slot::new(period, thread);
297+
let max_count = 4;
298+
let res = pool_command_sender
299+
.get_operation_batch(
300+
target_slot,
301+
OperationHashSet::default(),
302+
max_count,
303+
10000,
304+
)
305+
.await
306+
.unwrap();
307+
assert!(res
308+
.iter()
309+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))
310+
.eq(thread_tx_lists[target_slot.thread as usize]
311+
.iter()
312+
.filter(|(_, _, r)| r.contains(&target_slot.period))
313+
.take(max_count)
314+
.map(|(id, op, _)| (id, op.to_bytes_compact().unwrap()))));
315+
}
316+
}
317+
// Add transactions that should be ignored despite their high fees, due to them being too far in the future
318+
{
319+
pool_command_sender
320+
.update_current_slot(Slot::new(10, 0))
321+
.await
322+
.unwrap();
323+
let fee = 1000;
324+
let expire_period: u64 = 300;
325+
let (op, thread) = get_transaction(expire_period, fee);
326+
let id = op.verify_integrity().unwrap();
327+
let mut ops = OperationHashMap::default();
328+
ops.insert(id, op);
329+
330+
pool_command_sender.add_operations(ops).await.unwrap();
331+
332+
if let Some(cmd) = protocol_controller
333+
.wait_command(250.into(), op_filter)
334+
.await
335+
{
336+
panic!("unexpected protocol command {:?}", cmd)
337+
};
338+
let res = pool_command_sender
339+
.get_operation_batch(
340+
Slot::new(expire_period - 1, thread),
341+
OperationHashSet::default(),
342+
10,
343+
10000,
344+
)
345+
.await
346+
.unwrap();
347+
assert!(res.is_empty());
348+
}
349+
(protocol_controller, pool_command_sender, pool_manager)
350+
},
351+
)
352+
.await;
353+
}
354+
186355
#[tokio::test]
187356
#[serial]
188357
async fn test_pool_with_protocol_events() {
@@ -199,7 +368,7 @@ async fn test_pool_with_protocol_events() {
199368
_ => None,
200369
};
201370

202-
// generate transactions
371+
// generate (id, transactions, range of validity) by threads
203372
let mut thread_tx_lists = vec![Vec::new(); *thread_count as usize];
204373
for i in 0..18 {
205374
let fee = 40 + i;

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)