Skip to content

Commit 92285c1

Browse files
committed
mirror_worker: address lbaquerofierro review round 2 on PR 264
- Once at least one package is authenticated, a malformed later package is treated like truncation (persist the verified prefix, 202) instead of 400, matching the spec's "MUST respond 202 once one package was authenticated and saved". A malformed first package still 400s. - Do not cosign past the persisted frontier: the spec updates the mirror checkpoint to upload_end only once next_entry >= upload_end. A request that persists nothing (empty body, or all-already-persisted packages) with upload_end above the frontier now returns 202 to resume rather than signing a checkpoint at a size no tiles were written for.
1 parent 23ad875 commit 92285c1

1 file changed

Lines changed: 41 additions & 1 deletion

File tree

crates/mirror_worker/src/add_entries.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ fn content_type_is_octet_stream(headers: &axum::http::HeaderMap) -> bool {
233233
/// checkpoint.
234234
///
235235
/// [proc]: https://c2sp.org/tlog-mirror#processing
236+
#[allow(clippy::too_many_lines)]
236237
async fn verify_and_persist(
237238
env: &Env,
238239
header: &AddEntriesRequestHeader,
@@ -265,6 +266,19 @@ async fn verify_and_persist(
265266
break;
266267
}
267268
PackageOutcome::Err(e) => {
269+
// Spec: once at least one package has been authenticated
270+
// and saved the mirror MUST respond 202, not 400. Treat a
271+
// malformed later package like truncation so the verified
272+
// prefix is kept and the client resumes from the advanced
273+
// frontier; a malformed *first* package still 400s below.
274+
if packages_received > 0 {
275+
log::info!(
276+
"add-entries: malformed package [{pkg_start}, {pkg_end}) after \
277+
{packages_received} authenticated; treating as truncation: {e:?}"
278+
);
279+
truncated = true;
280+
break;
281+
}
268282
log::warn!("add-entries: malformed package [{pkg_start}, {pkg_end}): {e:?}");
269283
return Err(AppError::BadRequest(e.to_string()));
270284
}
@@ -336,6 +350,29 @@ async fn verify_and_persist(
336350
));
337351
}
338352

353+
// Spec: the mirror updates its checkpoint to `upload_end` only once
354+
// "the next entry will be greater or equal to `upload_end`", i.e. all
355+
// entries up to `upload_end` are durably persisted. A request that
356+
// persists nothing (e.g. an empty body, or one whose packages are all
357+
// already-persisted) must not let us cosign past our frontier: without
358+
// this guard `upload_end` above `next_entry` would sign a checkpoint at
359+
// a size we never wrote tiles for. When the frontier has not reached
360+
// `upload_end`, treat it like a truncated upload and 202 so the client
361+
// resumes from the advertised next entry.
362+
if frontier_size < header.upload_end {
363+
log::info!(
364+
"add-entries: frontier {frontier_size} below upload_end {}; nothing to persist \
365+
this request, returning 202 to resume",
366+
header.upload_end,
367+
);
368+
return Ok(mirror_info_202(
369+
env,
370+
snapshot,
371+
&header.log_origin,
372+
frontier_size,
373+
));
374+
}
375+
339376
// Every canonical package was received. Any bytes past the last one
340377
// are discarded, not rejected: the spec says "the mirror discards any
341378
// partial bytes after the last successfully authenticated entry
@@ -348,7 +385,10 @@ async fn verify_and_persist(
348385
// proof verification and tile computation disagree: an internal error,
349386
// never a client fault. When nothing new was persisted (a re-upload of
350387
// an already-persisted range), the log-signed target is trusted
351-
// directly.
388+
// directly: pending checkpoints are consistency-chained on the
389+
// add-checkpoint path and tickets only revive our own past pendings, so
390+
// the target is on the same branch as the persisted tree by
391+
// construction.
352392
if persisted_new && (frontier_size != header.upload_end || frontier_hash != target.hash) {
353393
log::error!(
354394
"add-entries: recomputed frontier ({frontier_size}, {frontier_hash}) != target ({}, {})",

0 commit comments

Comments
 (0)