Skip to content

Commit 954be8f

Browse files
fix(apollo_batcher): batcher returns error when l1_provider fail while commiting a block
1 parent 0fd33c7 commit 954be8f

File tree

2 files changed

+69
-19
lines changed

2 files changed

+69
-19
lines changed

crates/apollo_batcher/src/batcher.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,6 @@ impl Batcher {
568568
error!("Failed to commit proposal to storage: {}", err);
569569
BatcherError::InternalError
570570
})?;
571-
STORAGE_HEIGHT.increment(1);
572571

573572
// Notify the L1 provider of the new block.
574573
let rejected_l1_handler_tx_hashes = rejected_tx_hashes
@@ -585,21 +584,31 @@ impl Batcher {
585584
height,
586585
)
587586
.await;
588-
l1_provider_result.unwrap_or_else(|err| match err {
589-
L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight {
590-
expected_height,
591-
got,
592-
}) => {
593-
error!(
594-
"Unexpected height while committing block in L1 provider: expected={:?}, \
595-
got={:?}",
596-
expected_height, got
597-
);
598-
}
599-
other_err => {
600-
panic!("Unexpected error while committing block in L1 provider: {:?}", other_err)
587+
588+
// Return error if the commit to the L1 provider failed.
589+
if let Err(err) = l1_provider_result {
590+
match err {
591+
L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight {
592+
expected_height,
593+
got,
594+
}) => {
595+
error!(
596+
"Unexpected height while committing block in L1 provider: expected={:?}, \
597+
got={:?}",
598+
expected_height, got
599+
);
600+
}
601+
other_err => {
602+
error!(
603+
"Unexpected error while committing block in L1 provider: {:?}",
604+
other_err
605+
);
606+
}
601607
}
602-
});
608+
// Rollback the state diff in the storage.
609+
self.storage_writer.revert_block(height);
610+
return Err(BatcherError::InternalError);
611+
}
603612

604613
// Notify the mempool of the new block.
605614
let mempool_result = self
@@ -612,6 +621,7 @@ impl Batcher {
612621
// TODO(AlonH): Should we rollback the state diff and return an error?
613622
};
614623

624+
STORAGE_HEIGHT.increment(1);
615625
Ok(())
616626
}
617627

crates/apollo_batcher/src/batcher_test.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,12 @@ fn abort_signal_sender() -> AbortSignalSender {
168168

169169
async fn batcher_propose_and_commit_block(
170170
mock_dependencies: MockDependencies,
171-
) -> DecisionReachedResponse {
171+
) -> Result<DecisionReachedResponse, BatcherError> {
172172
let mut batcher = create_batcher(mock_dependencies).await;
173173
batcher.start_height(StartHeightInput { height: INITIAL_HEIGHT }).await.unwrap();
174174
batcher.propose_block(propose_block_input(PROPOSAL_ID)).await.unwrap();
175175
batcher.await_active_proposal().await;
176-
batcher.decision_reached(DecisionReachedInput { proposal_id: PROPOSAL_ID }).await.unwrap()
176+
batcher.decision_reached(DecisionReachedInput { proposal_id: PROPOSAL_ID }).await
177177
}
178178

179179
fn mock_create_builder_for_validate_block(
@@ -1000,7 +1000,8 @@ async fn decision_reached() {
10001000
Ok(BlockExecutionArtifacts::create_for_testing()),
10011001
);
10021002

1003-
let decision_reached_response = batcher_propose_and_commit_block(mock_dependencies).await;
1003+
let decision_reached_response =
1004+
batcher_propose_and_commit_block(mock_dependencies).await.unwrap();
10041005

10051006
verify_decision_reached_response(&decision_reached_response, &expected_artifacts);
10061007

@@ -1054,7 +1055,8 @@ async fn test_execution_info_order_is_kept() {
10541055
Ok(block_builder_result.clone()),
10551056
);
10561057

1057-
let decision_reached_response = batcher_propose_and_commit_block(mock_dependencies).await;
1058+
let decision_reached_response =
1059+
batcher_propose_and_commit_block(mock_dependencies).await.unwrap();
10581060

10591061
// Verify that the execution_infos are in the same order as returned from the block_builder.
10601062
let expected_execution_infos: Vec<TransactionExecutionInfo> =
@@ -1097,3 +1099,41 @@ fn validate_batcher_config_failure() {
10971099
.contains("input_stream_content_buffer_size must be at least tx_chunk_size")
10981100
);
10991101
}
1102+
1103+
#[rstest]
1104+
#[case::communication_failure(
1105+
L1ProviderClientError::ClientError(ClientError::CommunicationFailure("L1 commit failed".to_string()))
1106+
)]
1107+
#[case::unexpected_height(
1108+
L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight {
1109+
expected_height: INITIAL_HEIGHT,
1110+
got: INITIAL_HEIGHT,
1111+
})
1112+
)]
1113+
#[tokio::test]
1114+
async fn decision_reached_return_error_when_l1_commit_block_fails(
1115+
#[case] l1_error: L1ProviderClientError,
1116+
) {
1117+
let mut mock_dependencies = MockDependencies::default();
1118+
1119+
mock_dependencies.l1_provider_client.expect_start_block().returning(|_, _| Ok(()));
1120+
1121+
mock_dependencies
1122+
.l1_provider_client
1123+
.expect_commit_block()
1124+
.times(1)
1125+
.returning(move |_, _, _| Err(l1_error.clone()));
1126+
1127+
mock_dependencies.storage_writer.expect_commit_proposal().returning(|_, _| Ok(()));
1128+
1129+
mock_dependencies.storage_writer.expect_revert_block().returning(|_| ());
1130+
1131+
mock_create_builder_for_propose_block(
1132+
&mut mock_dependencies.block_builder_factory,
1133+
vec![],
1134+
Ok(BlockExecutionArtifacts::create_for_testing()),
1135+
);
1136+
1137+
let result = batcher_propose_and_commit_block(mock_dependencies).await;
1138+
assert!(result.is_err());
1139+
}

0 commit comments

Comments
 (0)