Skip to content

Commit a23f003

Browse files
authored
fix: batcher queue ord (#1664)
1 parent ee2db4f commit a23f003

File tree

2 files changed

+215
-3
lines changed

2 files changed

+215
-3
lines changed

batcher/aligned-batcher/src/connection.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ pub(crate) async fn send_batch_inclusion_data_responses(
2121
finalized_batch: Vec<BatchQueueEntry>,
2222
batch_merkle_tree: &MerkleTree<VerificationCommitmentBatch>,
2323
) -> Result<(), BatcherError> {
24-
for (vd_batch_idx, entry) in finalized_batch.iter().enumerate() {
24+
// Finalized_batch is ordered as the PriorityQueue, ordered by: ascending max_fee && if max_fee is equal, by descending nonce.
25+
// We iter it in reverse because each sender wants to receive responses in ascending nonce order
26+
for (vd_batch_idx, entry) in finalized_batch.iter().enumerate().rev() {
2527
let batch_inclusion_data = BatchInclusionData::new(
2628
vd_batch_idx,
2729
batch_merkle_tree,

batcher/aligned-batcher/src/types/batch_queue.rs

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,16 @@ impl PartialOrd for BatchQueueEntryPriority {
100100

101101
impl Ord for BatchQueueEntryPriority {
102102
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
103-
let ord = other.max_fee.cmp(&self.max_fee);
103+
// Implementation of lowest-first:
104+
let ord: std::cmp::Ordering = other.max_fee.cmp(&self.max_fee);
105+
// This means, less max_fee will go first
106+
// We want this because we will .pop() to remove unwanted elements, low fee submitions.
107+
104108
if ord == std::cmp::Ordering::Equal {
105-
self.nonce.cmp(&other.nonce).reverse()
109+
// Case of same max_fee:
110+
// Implementation of biggest-first:
111+
// Since we want to .pop() entries with biggest nonce first, because we want to submit low nonce first
112+
self.nonce.cmp(&other.nonce)
106113
} else {
107114
ord
108115
}
@@ -155,6 +162,7 @@ pub(crate) fn try_build_batch(
155162
let batch_len = finalized_batch.len();
156163
let fee_per_proof = calculate_fee_per_proof(batch_len, gas_price);
157164

165+
// if batch is not acceptable:
158166
if batch_size > max_batch_byte_size
159167
|| fee_per_proof > entry.nonced_verification_data.max_fee
160168
|| batch_len > max_batch_proof_qty
@@ -311,6 +319,208 @@ mod test {
311319
);
312320
}
313321

322+
#[test]
323+
fn batch_finalization_algorithm_works_from_same_sender_same_fee() {
324+
// The following information will be the same for each entry, it is just some dummy data to see
325+
// algorithm working.
326+
327+
let proof_generator_addr = Address::random();
328+
let payment_service_addr = Address::random();
329+
let sender_addr = Address::random();
330+
let bytes_for_verification_data = vec![42_u8; 10];
331+
let dummy_signature = Signature {
332+
r: U256::from(1),
333+
s: U256::from(2),
334+
v: 3,
335+
};
336+
let verification_data = VerificationData {
337+
proving_system: ProvingSystemId::Risc0,
338+
proof: bytes_for_verification_data.clone(),
339+
pub_input: Some(bytes_for_verification_data.clone()),
340+
verification_key: Some(bytes_for_verification_data.clone()),
341+
vm_program_code: Some(bytes_for_verification_data),
342+
proof_generator_addr,
343+
};
344+
let chain_id = U256::from(42);
345+
346+
// Here we create different entries for the batch queue.
347+
// All with the same fee
348+
349+
let max_fee = U256::from(130000000000000u128);
350+
351+
// Entry 1
352+
let nonce_1 = U256::from(1);
353+
let nonced_verification_data_1 = NoncedVerificationData::new(
354+
verification_data.clone(),
355+
nonce_1,
356+
max_fee,
357+
chain_id,
358+
payment_service_addr,
359+
);
360+
let vd_commitment_1: VerificationDataCommitment = nonced_verification_data_1.clone().into();
361+
let entry_1 = BatchQueueEntry::new_for_testing(
362+
nonced_verification_data_1,
363+
vd_commitment_1,
364+
dummy_signature,
365+
sender_addr,
366+
);
367+
let batch_priority_1 = BatchQueueEntryPriority::new(max_fee, nonce_1);
368+
369+
// Entry 2
370+
let nonce_2 = U256::from(2);
371+
let nonced_verification_data_2 = NoncedVerificationData::new(
372+
verification_data.clone(),
373+
nonce_2,
374+
max_fee,
375+
chain_id,
376+
payment_service_addr,
377+
);
378+
let vd_commitment_2: VerificationDataCommitment = nonced_verification_data_2.clone().into();
379+
let entry_2 = BatchQueueEntry::new_for_testing(
380+
nonced_verification_data_2,
381+
vd_commitment_2,
382+
dummy_signature,
383+
sender_addr,
384+
);
385+
let batch_priority_2 = BatchQueueEntryPriority::new(max_fee, nonce_2);
386+
387+
// Entry 3
388+
let nonce_3 = U256::from(3);
389+
let nonced_verification_data_3 = NoncedVerificationData::new(
390+
verification_data.clone(),
391+
nonce_3,
392+
max_fee,
393+
chain_id,
394+
payment_service_addr,
395+
);
396+
let vd_commitment_3: VerificationDataCommitment = nonced_verification_data_3.clone().into();
397+
let entry_3 = BatchQueueEntry::new_for_testing(
398+
nonced_verification_data_3,
399+
vd_commitment_3,
400+
dummy_signature,
401+
sender_addr,
402+
);
403+
let batch_priority_3 = BatchQueueEntryPriority::new(max_fee, nonce_3);
404+
405+
let mut batch_queue = BatchQueue::new();
406+
batch_queue.push(entry_1, batch_priority_1);
407+
batch_queue.push(entry_2, batch_priority_2);
408+
batch_queue.push(entry_3, batch_priority_3);
409+
410+
let gas_price = U256::from(1);
411+
let finalized_batch = try_build_batch(batch_queue.clone(), gas_price, 5000000, 50).unwrap();
412+
413+
// All entries from the batch queue should be in
414+
// the finalized batch.
415+
assert!(batch_queue.len() == 3);
416+
417+
assert_eq!(finalized_batch[0].nonced_verification_data.nonce, nonce_3);
418+
assert_eq!(finalized_batch[1].nonced_verification_data.nonce, nonce_2);
419+
assert_eq!(finalized_batch[2].nonced_verification_data.nonce, nonce_1);
420+
421+
// sanity check
422+
assert_eq!(finalized_batch[2].nonced_verification_data.max_fee, max_fee);
423+
}
424+
425+
#[test]
426+
fn batch_finalization_algorithm_works_from_same_sender_same_fee_nonempty_resulting_queue() {
427+
// The following information will be the same for each entry, it is just some dummy data to see
428+
// algorithm working.
429+
430+
let proof_generator_addr = Address::random();
431+
let payment_service_addr = Address::random();
432+
let sender_addr = Address::random();
433+
let bytes_for_verification_data = vec![42_u8; 10];
434+
let dummy_signature = Signature {
435+
r: U256::from(1),
436+
s: U256::from(2),
437+
v: 3,
438+
};
439+
let verification_data = VerificationData {
440+
proving_system: ProvingSystemId::Risc0,
441+
proof: bytes_for_verification_data.clone(),
442+
pub_input: Some(bytes_for_verification_data.clone()),
443+
verification_key: Some(bytes_for_verification_data.clone()),
444+
vm_program_code: Some(bytes_for_verification_data),
445+
proof_generator_addr,
446+
};
447+
let chain_id = U256::from(42);
448+
449+
// Here we create different entries for the batch queue.
450+
// All with the same fee
451+
452+
let max_fee = U256::from(130000000000000u128);
453+
454+
// Entry 1
455+
let nonce_1 = U256::from(1);
456+
let nonced_verification_data_1 = NoncedVerificationData::new(
457+
verification_data.clone(),
458+
nonce_1,
459+
max_fee,
460+
chain_id,
461+
payment_service_addr,
462+
);
463+
let vd_commitment_1: VerificationDataCommitment = nonced_verification_data_1.clone().into();
464+
let entry_1 = BatchQueueEntry::new_for_testing(
465+
nonced_verification_data_1,
466+
vd_commitment_1,
467+
dummy_signature,
468+
sender_addr,
469+
);
470+
let batch_priority_1 = BatchQueueEntryPriority::new(max_fee, nonce_1);
471+
472+
// Entry 2
473+
let nonce_2 = U256::from(2);
474+
let nonced_verification_data_2 = NoncedVerificationData::new(
475+
verification_data.clone(),
476+
nonce_2,
477+
max_fee,
478+
chain_id,
479+
payment_service_addr,
480+
);
481+
let vd_commitment_2: VerificationDataCommitment = nonced_verification_data_2.clone().into();
482+
let entry_2 = BatchQueueEntry::new_for_testing(
483+
nonced_verification_data_2,
484+
vd_commitment_2,
485+
dummy_signature,
486+
sender_addr,
487+
);
488+
let batch_priority_2 = BatchQueueEntryPriority::new(max_fee, nonce_2);
489+
490+
// Entry 3
491+
let nonce_3 = U256::from(3);
492+
let nonced_verification_data_3 = NoncedVerificationData::new(
493+
verification_data.clone(),
494+
nonce_3,
495+
max_fee,
496+
chain_id,
497+
payment_service_addr,
498+
);
499+
let vd_commitment_3: VerificationDataCommitment = nonced_verification_data_3.clone().into();
500+
let entry_3 = BatchQueueEntry::new_for_testing(
501+
nonced_verification_data_3,
502+
vd_commitment_3,
503+
dummy_signature,
504+
sender_addr,
505+
);
506+
let batch_priority_3 = BatchQueueEntryPriority::new(max_fee, nonce_3);
507+
508+
let mut batch_queue = BatchQueue::new();
509+
batch_queue.push(entry_1, batch_priority_1);
510+
batch_queue.push(entry_2, batch_priority_2);
511+
batch_queue.push(entry_3.clone(), batch_priority_3.clone());
512+
513+
let gas_price = U256::from(1);
514+
let finalized_batch = try_build_batch(batch_queue.clone(), gas_price, 5000000, 2).unwrap();
515+
516+
// One Entry from the batch_queue should not be in the finalized batch
517+
// Particularly, nonce_3 is not in the finalized batch
518+
assert!(batch_queue.len() == 3);
519+
520+
assert_eq!(finalized_batch[0].nonced_verification_data.nonce, nonce_2);
521+
assert_eq!(finalized_batch[1].nonced_verification_data.nonce, nonce_1);
522+
}
523+
314524
#[test]
315525
fn batch_finalization_algorithm_works_from_different_senders() {
316526
// The following information will be the same for each entry, it is just some dummy data to see

0 commit comments

Comments
 (0)