Skip to content

Commit 0602e6d

Browse files
feat: batcher should not be able to build batches too big (#1410)
Co-authored-by: Marcos Nicolau <[email protected]>
1 parent ff0bac6 commit 0602e6d

File tree

8 files changed

+151
-29
lines changed

8 files changed

+151
-29
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ batcher_send_plonk_bn254_burst: batcher/target/release/aligned
410410
--vk ../../scripts/test_files/gnark_plonk_bn254_script/plonk.vk \
411411
--proof_generator_addr 0x66f9664f97F2b50F62D13eA064982f936dE76657 \
412412
--rpc_url $(RPC_URL) \
413-
--repetitions 4 \
413+
--repetitions $(BURST_SIZE) \
414414
--network $(NETWORK)
415415

416416
batcher_send_plonk_bls12_381_task: batcher/target/release/aligned

batcher/aligned-batcher/src/config/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ pub struct BatcherConfigFromYaml {
4040
pub block_interval: u64,
4141
pub transaction_wait_timeout: u64,
4242
pub max_proof_size: usize,
43-
pub max_batch_size: usize,
43+
pub max_batch_byte_size: usize,
44+
pub max_batch_proof_qty: usize,
4445
pub pre_verification_is_enabled: bool,
4546
pub metrics_port: u16,
4647
pub telemetry_ip_port_address: String,

batcher/aligned-batcher/src/lib.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ pub struct Batcher {
8282
max_block_interval: u64,
8383
transaction_wait_timeout: u64,
8484
max_proof_size: usize,
85-
max_batch_size: usize,
85+
max_batch_byte_size: usize,
86+
max_batch_proof_qty: usize,
8687
last_uploaded_batch_block: Mutex<u64>,
8788
pre_verification_is_enabled: bool,
8889
non_paying_config: Option<NonPayingConfig>,
@@ -244,7 +245,8 @@ impl Batcher {
244245
max_block_interval: config.batcher.block_interval,
245246
transaction_wait_timeout: config.batcher.transaction_wait_timeout,
246247
max_proof_size: config.batcher.max_proof_size,
247-
max_batch_size: config.batcher.max_batch_size,
248+
max_batch_byte_size: config.batcher.max_batch_byte_size,
249+
max_batch_proof_qty: config.batcher.max_batch_proof_qty,
248250
last_uploaded_batch_block: Mutex::new(last_uploaded_batch_block),
249251
pre_verification_is_enabled: config.batcher.pre_verification_is_enabled,
250252
non_paying_config,
@@ -1055,21 +1057,25 @@ impl Batcher {
10551057
// Set the batch posting flag to true
10561058
*batch_posting = true;
10571059
let batch_queue_copy = batch_state_lock.batch_queue.clone();
1058-
let (resulting_batch_queue, finalized_batch) =
1059-
batch_queue::try_build_batch(batch_queue_copy, gas_price, self.max_batch_size)
1060-
.inspect_err(|e| {
1061-
*batch_posting = false;
1062-
match e {
1063-
// We can't post a batch since users are not willing to pay the needed fee, wait for more proofs
1064-
BatcherError::BatchCostTooHigh => {
1065-
info!("No working batch found. Waiting for more proofs")
1066-
}
1067-
// FIXME: We should refactor this code and instead of returning None, return an error.
1068-
// See issue https://github.com/yetanotherco/aligned_layer/issues/1046.
1069-
e => error!("Unexpected error: {:?}", e),
1070-
}
1071-
})
1072-
.ok()?;
1060+
let (resulting_batch_queue, finalized_batch) = batch_queue::try_build_batch(
1061+
batch_queue_copy,
1062+
gas_price,
1063+
self.max_batch_byte_size,
1064+
self.max_batch_proof_qty,
1065+
)
1066+
.inspect_err(|e| {
1067+
*batch_posting = false;
1068+
match e {
1069+
// We can't post a batch since users are not willing to pay the needed fee, wait for more proofs
1070+
BatcherError::BatchCostTooHigh => {
1071+
info!("No working batch found. Waiting for more proofs")
1072+
}
1073+
// FIXME: We should refactor this code and instead of returning None, return an error.
1074+
// See issue https://github.com/yetanotherco/aligned_layer/issues/1046.
1075+
e => error!("Unexpected error: {:?}", e),
1076+
}
1077+
})
1078+
.ok()?;
10731079

10741080
batch_state_lock.batch_queue = resulting_batch_queue;
10751081
let updated_user_proof_count_and_min_fee =

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

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ pub(crate) fn calculate_batch_size(batch_queue: &BatchQueue) -> Result<usize, Ba
146146
pub(crate) fn try_build_batch(
147147
batch_queue: BatchQueue,
148148
gas_price: U256,
149-
max_batch_size: usize,
149+
max_batch_byte_size: usize,
150+
max_batch_proof_qty: usize,
150151
) -> Result<(BatchQueue, Vec<BatchQueueEntry>), BatcherError> {
151152
let mut batch_queue = batch_queue;
152153
let mut batch_size = calculate_batch_size(&batch_queue)?;
@@ -156,7 +157,10 @@ pub(crate) fn try_build_batch(
156157
let batch_len = batch_queue.len();
157158
let fee_per_proof = calculate_fee_per_proof(batch_len, gas_price);
158159

159-
if batch_size > max_batch_size || fee_per_proof > entry.nonced_verification_data.max_fee {
160+
if batch_size > max_batch_byte_size
161+
|| fee_per_proof > entry.nonced_verification_data.max_fee
162+
|| batch_len > max_batch_proof_qty
163+
{
160164
// Update the state for the next iteration:
161165
// * Subtract this entry size to the size of the batch size.
162166
// * Push the current entry to the resulting batch queue.
@@ -298,7 +302,7 @@ mod test {
298302

299303
let gas_price = U256::from(1);
300304
let (resulting_batch_queue, batch) =
301-
try_build_batch(batch_queue, gas_price, 5000000).unwrap();
305+
try_build_batch(batch_queue, gas_price, 5000000, 50).unwrap();
302306

303307
assert!(resulting_batch_queue.is_empty());
304308

@@ -401,7 +405,7 @@ mod test {
401405

402406
let gas_price = U256::from(1);
403407
let (resulting_batch_queue, finalized_batch) =
404-
try_build_batch(batch_queue, gas_price, 5000000).unwrap();
408+
try_build_batch(batch_queue, gas_price, 5000000, 50).unwrap();
405409

406410
// The resulting batch queue (entries from the old batch queue that were not willing to pay
407411
// in this batch), should be empty and hence, all entries from the batch queue should be in
@@ -512,7 +516,7 @@ mod test {
512516

513517
let gas_price = U256::from(1);
514518
let (resulting_batch_queue, finalized_batch) =
515-
try_build_batch(batch_queue, gas_price, 5000000).unwrap();
519+
try_build_batch(batch_queue, gas_price, 5000000, 50).unwrap();
516520

517521
// The resulting batch queue (entries from the old batch queue that were not willing to pay
518522
// in this batch), should be empty and hence, all entries from the batch queue should be in
@@ -529,4 +533,113 @@ mod test {
529533
max_fee_1
530534
);
531535
}
536+
537+
#[test]
538+
fn batch_finalization_algorithm_works_not_bigger_than_max_batch_proof_qty() {
539+
// The following information will be the same for each entry, it is just some dummy data to see
540+
// algorithm working.
541+
542+
let proof_generator_addr = Address::random();
543+
let payment_service_addr = Address::random();
544+
let sender_addr = Address::random();
545+
let bytes_for_verification_data = vec![42_u8; 10];
546+
let dummy_signature = Signature {
547+
r: U256::from(1),
548+
s: U256::from(2),
549+
v: 3,
550+
};
551+
let verification_data = VerificationData {
552+
proving_system: ProvingSystemId::Risc0,
553+
proof: bytes_for_verification_data.clone(),
554+
pub_input: Some(bytes_for_verification_data.clone()),
555+
verification_key: Some(bytes_for_verification_data.clone()),
556+
vm_program_code: Some(bytes_for_verification_data),
557+
proof_generator_addr,
558+
};
559+
let chain_id = U256::from(42);
560+
561+
// Here we create different entries for the batch queue.
562+
// Since we are sending with the same address, the low nonces should have higher max fees.
563+
564+
// Entry 1
565+
let nonce_1 = U256::from(1);
566+
let max_fee_1 = U256::from(1_300_000_000_000_002u128);
567+
let nonced_verification_data_1 = NoncedVerificationData::new(
568+
verification_data.clone(),
569+
nonce_1,
570+
max_fee_1,
571+
chain_id,
572+
payment_service_addr,
573+
);
574+
let vd_commitment_1: VerificationDataCommitment = nonced_verification_data_1.clone().into();
575+
let entry_1 = BatchQueueEntry::new_for_testing(
576+
nonced_verification_data_1,
577+
vd_commitment_1,
578+
dummy_signature,
579+
sender_addr,
580+
);
581+
let batch_priority_1 = BatchQueueEntryPriority::new(max_fee_1, nonce_1);
582+
583+
// Entry 2
584+
let nonce_2 = U256::from(2);
585+
let max_fee_2 = U256::from(1_300_000_000_000_001u128);
586+
let nonced_verification_data_2 = NoncedVerificationData::new(
587+
verification_data.clone(),
588+
nonce_2,
589+
max_fee_2,
590+
chain_id,
591+
payment_service_addr,
592+
);
593+
let vd_commitment_2: VerificationDataCommitment = nonced_verification_data_2.clone().into();
594+
let entry_2 = BatchQueueEntry::new_for_testing(
595+
nonced_verification_data_2,
596+
vd_commitment_2,
597+
dummy_signature,
598+
sender_addr,
599+
);
600+
let batch_priority_2 = BatchQueueEntryPriority::new(max_fee_2, nonce_2);
601+
602+
// Entry 3
603+
let nonce_3 = U256::from(3);
604+
let max_fee_3 = U256::from(1_300_000_000_000_000u128);
605+
let nonced_verification_data_3 = NoncedVerificationData::new(
606+
verification_data.clone(),
607+
nonce_3,
608+
max_fee_3,
609+
chain_id,
610+
payment_service_addr,
611+
);
612+
let vd_commitment_3: VerificationDataCommitment = nonced_verification_data_3.clone().into();
613+
let entry_3 = BatchQueueEntry::new_for_testing(
614+
nonced_verification_data_3,
615+
vd_commitment_3,
616+
dummy_signature,
617+
sender_addr,
618+
);
619+
let batch_priority_3 = BatchQueueEntryPriority::new(max_fee_3, nonce_3);
620+
621+
let mut batch_queue = BatchQueue::new();
622+
batch_queue.push(entry_1, batch_priority_1);
623+
batch_queue.push(entry_2, batch_priority_2);
624+
batch_queue.push(entry_3, batch_priority_3);
625+
626+
let gas_price = U256::from(1);
627+
628+
// The max batch len is 2, so the algorithm should stop at the second entry.
629+
let max_batch_proof_qty = 2;
630+
631+
let (resulting_batch_queue, finalized_batch) =
632+
try_build_batch(batch_queue, gas_price, 5000000, max_batch_proof_qty).unwrap();
633+
634+
assert_eq!(resulting_batch_queue.len(), 1);
635+
assert_eq!(finalized_batch.len(), 2);
636+
assert_eq!(
637+
finalized_batch[0].nonced_verification_data.max_fee,
638+
max_fee_2
639+
);
640+
assert_eq!(
641+
finalized_batch[1].nonced_verification_data.max_fee,
642+
max_fee_1
643+
);
644+
}
532645
}

config-files/config-batcher-docker.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ batcher:
2020
batch_size_interval: 10
2121
transaction_wait_timeout: 36000 # 3 blocks
2222
max_proof_size: 67108864 # 64 MiB
23-
max_batch_size: 268435456 # 256 MiB
23+
max_batch_byte_size: 268435456 # 256 MiB
24+
max_batch_proof_qty: 3000 # 3000 proofs in a batch
2425
eth_ws_reconnects: 99999999999999
2526
pre_verification_is_enabled: true
2627
metrics_port: 9093

config-files/config-batcher.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ batcher:
2020
batch_size_interval: 10
2121
transaction_wait_timeout: 36000 # 3 blocks
2222
max_proof_size: 67108864 # 64 MiB
23-
max_batch_size: 268435456 # 256 MiB
23+
max_batch_byte_size: 268435456 # 256 MiB
24+
max_batch_proof_qty: 3000 # 3000 proofs in a batch
2425
pre_verification_is_enabled: true
2526
metrics_port: 9093
2627
telemetry_ip_port_address: localhost:4001

config-files/config-docker.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ batcher:
2424
block_interval: 3
2525
batch_size_interval: 10
2626
max_proof_size: 67108864 # 64 MiB
27-
max_batch_size: 268435456 # 256 MiB
27+
max_batch_byte_size: 268435456 # 256 MiB
2828
eth_ws_reconnects: 99999999999999
2929
pre_verification_is_enabled: true
3030

@@ -47,7 +47,7 @@ operator:
4747
metadata_url: "https://yetanotherco.github.io/operator_metadata/metadata.json"
4848
enable_metrics: true
4949
metrics_ip_port_address: localhost:9092
50-
max_batch_size: 268435456 # 256 MiB
50+
max_batch_byte_size: 268435456 # 256 MiB
5151
last_processed_batch_filepath: config-files/operator.last_processed_batch.json
5252
# Operators variables needed for register it in EigenLayer
5353
el_delegation_manager_address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9"

config-files/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ batcher:
2424
block_interval: 3
2525
batch_size_interval: 10
2626
max_proof_size: 67108864 # 64 MiB
27-
max_batch_size: 268435456 # 256 MiB
27+
max_batch_byte_size: 268435456 # 256 MiB
2828
pre_verification_is_enabled: true
2929
metrics_port: 9093
3030

0 commit comments

Comments
 (0)