Skip to content

Commit 1923e8b

Browse files
afckclaude
andcommitted
More complete RevertConfirm requests. (linera-io#5900)
## Motivation In some cases we send `RevertConfirm` with the lowest height that we _know_ we are missing. We should instead request the lowest height we _don't_ know we are _not_ missing, to make it more likely that we really get _all_ events. ## Proposal Rename the field and request the next expected height. ## Test Plan CI ## Release Plan - Hotfix validators - Port to `main`. ## Links - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a4d5270 commit 1923e8b

7 files changed

Lines changed: 40 additions & 41 deletions

File tree

linera-core/src/chain_worker/actor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ where
191191
/// Handle a `RevertConfirm` request to re-add outbox entries and resend bundles.
192192
HandleRevertConfirm {
193193
recipient: ChainId,
194-
missing_height: BlockHeight,
194+
retransmit_from: BlockHeight,
195195
#[debug(skip)]
196196
callback: oneshot::Sender<Result<NetworkActions, WorkerError>>,
197197
},

linera-core/src/chain_worker/state.rs

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,12 @@ pub(crate) enum CrossChainUpdateResult {
104104
Updated(BlockHeight),
105105
/// All bundles were already received; nothing to do.
106106
NothingToDo,
107-
/// A gap was detected: the inbox expected a bundle at `missing_height` from `origin`
108-
/// but received a bundle at a higher height. If `allow_revert_confirm` is enabled,
109-
/// a `RevertConfirm` request should be sent.
107+
/// A gap was detected in the inbox for messages from `origin`. If
108+
/// `allow_revert_confirm` is enabled, a `RevertConfirm` request should be sent
109+
/// to retransmit bundles starting from `retransmit_from`.
110110
GapDetected {
111111
origin: ChainId,
112-
missing_height: BlockHeight,
112+
retransmit_from: BlockHeight,
113113
},
114114
}
115115

@@ -260,10 +260,10 @@ where
260260
.is_ok(),
261261
ChainWorkerRequest::HandleRevertConfirm {
262262
recipient,
263-
missing_height,
263+
retransmit_from,
264264
callback,
265265
} => callback
266-
.send(self.handle_revert_confirm(recipient, missing_height).await)
266+
.send(self.handle_revert_confirm(recipient, retransmit_from).await)
267267
.is_ok(),
268268
ChainWorkerRequest::HandleChainInfoQuery { query, callback } => callback
269269
.send(self.handle_chain_info_query(query).await)
@@ -1055,22 +1055,21 @@ where
10551055
.await
10561056
{
10571057
Ok(()) => {}
1058-
Err(ChainError::InboxGapDetected {
1059-
origin,
1060-
expected_height,
1061-
..
1062-
}) if self.config.allow_revert_confirm => {
1058+
Err(ChainError::InboxGapDetected { origin, .. })
1059+
if self.config.allow_revert_confirm =>
1060+
{
1061+
let retransmit_from = self.get_inbox_next_height(origin).await?;
10631062
warn!(
10641063
"Inbox gap detected for {chain_id} from {origin}: \
1065-
missing height {expected_height}; requesting resend",
1064+
requesting resend from {retransmit_from}",
10661065
);
10671066
let mut actions = NetworkActions::default();
10681067
actions
10691068
.cross_chain_requests
10701069
.push(CrossChainRequest::RevertConfirm {
10711070
sender: origin,
10721071
recipient: chain_id,
1073-
missing_height: expected_height,
1072+
retransmit_from,
10741073
});
10751074
return Ok((self.chain_info_response(), actions, BlockOutcome::Skipped));
10761075
}
@@ -1223,7 +1222,7 @@ where
12231222
);
12241223
return Ok(CrossChainUpdateResult::GapDetected {
12251224
origin,
1226-
missing_height: prev,
1225+
retransmit_from: next_height_to_receive,
12271226
});
12281227
}
12291228
return Err(ChainError::InboxGapDetected {
@@ -1267,18 +1266,18 @@ where
12671266
.await
12681267
{
12691268
Ok(()) => {}
1270-
Err(ChainError::InboxGapDetected {
1271-
expected_height, ..
1272-
}) if self.config.allow_revert_confirm => {
1269+
Err(ChainError::InboxGapDetected { .. }) if self.config.allow_revert_confirm => {
12731270
// Don't save — leave the inbox unchanged so the resend can
1274-
// reconcile properly.
1271+
// reconcile properly. Request from next_height_to_receive
1272+
// rather than the specific gap height, so that all pending
1273+
// removed_bundles entries can also be reconciled.
12751274
warn!(
12761275
"Inbox gap detected for {recipient} from {origin}: \
1277-
missing height {expected_height}; requesting resend",
1276+
requesting resend from {next_height_to_receive}",
12781277
);
12791278
return Ok(CrossChainUpdateResult::GapDetected {
12801279
origin,
1281-
missing_height: expected_height,
1280+
retransmit_from: next_height_to_receive,
12821281
});
12831282
}
12841283
Err(e) => return Err(e.into()),
@@ -1336,28 +1335,28 @@ where
13361335

13371336
/// Handles a `RevertConfirm` request: walks backward through
13381337
/// `previous_message_blocks` to find all block heights that sent messages to
1339-
/// `recipient` starting from the latest down to `missing_height`, re-adds them
1338+
/// `recipient` starting from the latest down to `retransmit_from`, re-adds them
13401339
/// to the outbox, and creates cross-chain update actions to resend the bundles.
13411340
#[instrument(skip_all, fields(
13421341
chain_id = %self.chain_id(),
1343-
recipient = %recipient,
1344-
missing_height = %missing_height,
1342+
%recipient,
1343+
%retransmit_from,
13451344
))]
13461345
pub(super) async fn handle_revert_confirm(
13471346
&mut self,
13481347
recipient: ChainId,
1349-
missing_height: BlockHeight,
1348+
retransmit_from: BlockHeight,
13501349
) -> Result<NetworkActions, WorkerError> {
13511350
// 1. Walk backward through previous_message_blocks to collect all heights
1352-
// that sent messages to this recipient, from the latest down to missing_height.
1351+
// that sent messages to this recipient, from the latest down to retransmit_from.
13531352
let Some(latest_height) = self.chain.previous_message_blocks.get(&recipient).await? else {
13541353
warn!("RevertConfirm: no record of sending to {recipient}");
13551354
return Ok(NetworkActions::default());
13561355
};
13571356

13581357
let mut heights_to_re_add = Vec::new();
13591358
let mut current_height = latest_height;
1360-
while current_height >= missing_height {
1359+
while current_height >= retransmit_from {
13611360
// We arrived at current_height via previous_message_blocks links, starting from the
13621361
// chain state and following the links downwards. So these blocks should all be in
13631362
// confirmed_log or preprocessed_blocks already.
@@ -1381,7 +1380,7 @@ where
13811380
chain_id: self.chain_id(),
13821381
})?;
13831382
match block.block().body.previous_message_blocks.get(&recipient) {
1384-
Some((_, prev_height)) if *prev_height >= missing_height => {
1383+
Some((_, prev_height)) if *prev_height >= retransmit_from => {
13851384
current_height = *prev_height;
13861385
}
13871386
_ => break,
@@ -1419,7 +1418,7 @@ where
14191418

14201419
warn!(
14211420
"RevertConfirm: re-added {new_heights_len} heights to outbox for {recipient}, \
1422-
starting from height {missing_height}"
1421+
starting from height {retransmit_from}"
14231422
);
14241423

14251424
Ok(actions)
@@ -1486,7 +1485,7 @@ where
14861485
.push(CrossChainRequest::RevertConfirm {
14871486
sender: sender_id,
14881487
recipient: chain_id,
1489-
missing_height: BlockHeight::ZERO,
1488+
retransmit_from: BlockHeight::ZERO,
14901489
});
14911490
}
14921491

linera-core/src/data_types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ pub enum CrossChainRequest {
267267
RevertConfirm {
268268
sender: ChainId,
269269
recipient: ChainId,
270-
missing_height: BlockHeight,
270+
retransmit_from: BlockHeight,
271271
},
272272
}
273273

linera-core/src/worker.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,14 +1362,14 @@ where
13621362
}
13631363
CrossChainUpdateResult::GapDetected {
13641364
origin,
1365-
missing_height,
1365+
retransmit_from,
13661366
} => {
13671367
actions
13681368
.cross_chain_requests
13691369
.push(CrossChainRequest::RevertConfirm {
13701370
sender: origin,
13711371
recipient,
1372-
missing_height,
1372+
retransmit_from,
13731373
});
13741374
}
13751375
}
@@ -1394,12 +1394,12 @@ where
13941394
CrossChainRequest::RevertConfirm {
13951395
sender,
13961396
recipient,
1397-
missing_height,
1397+
retransmit_from,
13981398
} => {
13991399
self.query_chain_worker(sender, move |callback| {
14001400
ChainWorkerRequest::HandleRevertConfirm {
14011401
recipient,
1402-
missing_height,
1402+
retransmit_from,
14031403
callback,
14041404
}
14051405
})

linera-rpc/proto/rpc.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ message ConfirmUpdatedRecipient {
217217
message RevertConfirm {
218218
ChainId sender = 1;
219219
ChainId recipient = 2;
220-
BlockHeight missing_height = 3;
220+
BlockHeight retransmit_from = 3;
221221
}
222222

223223
// Request information on a chain.

linera-rpc/src/grpc/conversions.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,11 @@ impl TryFrom<api::CrossChainRequest> for CrossChainRequest {
308308
Inner::RevertConfirm(api::RevertConfirm {
309309
sender,
310310
recipient,
311-
missing_height,
311+
retransmit_from,
312312
}) => CrossChainRequest::RevertConfirm {
313313
sender: try_proto_convert(sender)?,
314314
recipient: try_proto_convert(recipient)?,
315-
missing_height: missing_height
315+
retransmit_from: retransmit_from
316316
.ok_or(GrpcProtoConversionError::MissingField)?
317317
.into(),
318318
},
@@ -351,11 +351,11 @@ impl TryFrom<CrossChainRequest> for api::CrossChainRequest {
351351
CrossChainRequest::RevertConfirm {
352352
sender,
353353
recipient,
354-
missing_height,
354+
retransmit_from,
355355
} => Inner::RevertConfirm(api::RevertConfirm {
356356
sender: Some(sender.into()),
357357
recipient: Some(recipient.into()),
358-
missing_height: Some(missing_height.into()),
358+
retransmit_from: Some(retransmit_from.into()),
359359
}),
360360
};
361361
Ok(Self { inner: Some(inner) })

linera-rpc/tests/snapshots/format__format.yaml.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ CrossChainRequest:
498498
TYPENAME: ChainId
499499
- recipient:
500500
TYPENAME: ChainId
501-
- missing_height:
501+
- retransmit_from:
502502
TYPENAME: BlockHeight
503503
CryptoHash:
504504
NEWTYPESTRUCT:

0 commit comments

Comments
 (0)