Skip to content

Commit 630f43a

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

File tree

2 files changed

+74
-18
lines changed

2 files changed

+74
-18
lines changed

crates/apollo_batcher/src/batcher.rs

+26-14
Original file line numberDiff line numberDiff line change
@@ -585,21 +585,33 @@ impl Batcher {
585585
height,
586586
)
587587
.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)
588+
589+
// Return error if the commit to the L1 provider failed.
590+
if let Err(err) = l1_provider_result {
591+
match err {
592+
L1ProviderClientError::L1ProviderError(L1ProviderError::UnexpectedHeight {
593+
expected_height,
594+
got,
595+
}) => {
596+
error!(
597+
"Unexpected height while committing block in L1 provider: expected={:?}, \
598+
got={:?}",
599+
expected_height, got
600+
);
601+
}
602+
other_err => {
603+
error!(
604+
"Unexpected error while committing block in L1 provider: {:?}",
605+
other_err
606+
);
607+
}
601608
}
602-
});
609+
// Rollback the state diff in the storage.
610+
self.storage_writer.revert_block(height);
611+
STORAGE_HEIGHT.decrement(1);
612+
REVERTED_BLOCKS.increment(1);
613+
return Err(BatcherError::InternalError);
614+
}
603615

604616
// Notify the mempool of the new block.
605617
let mempool_result = self

crates/apollo_batcher/src/batcher_test.rs

+48-4
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,45 @@ 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+
// Setup mocks
1118+
let mut mock_dependencies = MockDependencies::default();
1119+
1120+
mock_dependencies.l1_provider_client.expect_start_block().returning(|_, _| Ok(()));
1121+
1122+
mock_dependencies
1123+
.l1_provider_client
1124+
.expect_commit_block()
1125+
.times(1)
1126+
.returning(move |_, _, _| Err(l1_error.clone()));
1127+
1128+
mock_dependencies.mempool_client.expect_commit_block().times(1).returning(|_| Ok(()));
1129+
1130+
mock_dependencies.storage_writer.expect_commit_proposal().returning(|_, _| Ok(()));
1131+
1132+
mock_dependencies.storage_writer.expect_revert_block().returning(|_| ());
1133+
1134+
// let expected_artifacts = BlockExecutionArtifacts::create_for_testing();
1135+
mock_create_builder_for_propose_block(
1136+
&mut mock_dependencies.block_builder_factory,
1137+
vec![],
1138+
Ok(BlockExecutionArtifacts::create_for_testing()),
1139+
);
1140+
1141+
let result = batcher_propose_and_commit_block(mock_dependencies).await;
1142+
assert!(result.is_err());
1143+
}

0 commit comments

Comments
 (0)