@@ -45,8 +45,8 @@ use signed_note::{NoteError, NoteVerifier, VerifierList};
4545use tlog_checkpoint:: { CheckpointSigner as _, CheckpointText } ;
4646use tlog_core:: { Subtree , verify_subtree_consistency_proof} ;
4747use tlog_witness:: {
48- AddCheckpointRequest , CONTENT_TYPE_TLOG_SIZE , SignSubtreeRequest , parse_add_checkpoint_request ,
49- parse_sign_subtree_request, serialize_sign_subtree_response,
48+ AddCheckpointRequest , CONTENT_TYPE_TLOG_SIZE , MAX_REQUEST_BODY_SIZE , SignSubtreeRequest ,
49+ parse_add_checkpoint_request , parse_sign_subtree_request, serialize_sign_subtree_response,
5050} ;
5151use tower_service:: Service as _;
5252#[ allow( clippy:: wildcard_imports) ]
@@ -87,7 +87,7 @@ async fn fetch(
8787 )
8888 . route (
8989 "/sign-subtree" ,
90- post ( sign_subtree) . layer ( DefaultBodyLimit :: max ( MAX_SIGN_SUBTREE_BODY_SIZE ) ) ,
90+ post ( sign_subtree) . layer ( DefaultBodyLimit :: max ( MAX_REQUEST_BODY_SIZE ) ) ,
9191 )
9292 . route ( "/metadata" , get ( metadata) )
9393 . route ( "/" , get ( root) )
@@ -386,25 +386,33 @@ async fn sign_subtree(State(env): State<Env>, body: Bytes) -> ApiResult<axum::re
386386 Ok ( t) => t,
387387 Err ( e) => {
388388 log:: warn!( "sign-subtree: malformed checkpoint text: {e:?}" ) ;
389- return Err ( AppError :: BadRequest ( format ! ( "{e:?}" ) ) ) ;
389+ return Err ( AppError :: BadRequest ( e . to_string ( ) ) ) ;
390390 }
391391 } ;
392392 if subtree_end > cp_text. size ( ) {
393+ log:: info!(
394+ "sign-subtree: subtree end {subtree_end} exceeds checkpoint size {}" ,
395+ cp_text. size( )
396+ ) ;
393397 return Err ( AppError :: BadRequest ( format ! (
394398 "subtree end {subtree_end} > checkpoint size {}" ,
395399 cp_text. size( )
396400 ) ) ) ;
397401 }
398402 let subtree = match Subtree :: new ( subtree_start, subtree_end) {
399403 Ok ( s) => s,
400- Err ( e) => return Err ( AppError :: BadRequest ( format ! ( "invalid subtree: {e:?}" ) ) ) ,
404+ Err ( e) => {
405+ log:: info!( "sign-subtree: invalid subtree [{subtree_start}, {subtree_end}): {e:?}" ) ;
406+ return Err ( AppError :: BadRequest ( format ! ( "invalid subtree: {e:?}" ) ) ) ;
407+ }
401408 } ;
402409
403410 // Look up the log by its origin. Subtree DoS-protection cosignatures
404411 // in the request are ignored: this implementation applies no
405412 // pre-screening policy, as the spec leaves their use to the operator.
406413 let origin = cp_text. origin ( ) ;
407414 if log_verifiers ( origin) . is_none ( ) {
415+ log:: info!( "sign-subtree: unknown log origin {origin:?}" ) ;
408416 return Err ( AppError :: UnknownLogOrigin ) ;
409417 }
410418
@@ -420,9 +428,13 @@ async fn sign_subtree(State(env): State<Env>, body: Bytes) -> ApiResult<axum::re
420428 log:: info!( "sign-subtree: reference checkpoint not cosigned by this mirror: {e:?}" ) ;
421429 return Err ( AppError :: ReferenceCheckpointNotCosignedByThisMirror ) ;
422430 }
431+ // `MismatchedVerifier`/`AmbiguousKey` mean the verifier list
432+ // we built is malformed, not that the client sent a bad
433+ // request; over a one-element list they are unreachable
434+ // today. Surface them as 500 rather than blaming the client.
423435 _ => {
424- log:: warn !( "sign-subtree: checkpoint verify failed: {e:?}" ) ;
425- return Err ( AppError :: BadRequest ( e. to_string ( ) ) ) ;
436+ log:: error !( "sign-subtree: checkpoint verify failed unexpectedly : {e:?}" ) ;
437+ return Err ( AppError :: InternalServerError ( e. to_string ( ) ) ) ;
426438 }
427439 }
428440 }
@@ -438,6 +450,11 @@ async fn sign_subtree(State(env): State<Env>, body: Bytes) -> ApiResult<axum::re
438450 )
439451 . is_err ( )
440452 {
453+ log:: info!(
454+ "sign-subtree: consistency proof failed for subtree [{subtree_start}, {subtree_end}) \
455+ against checkpoint size {}",
456+ cp_text. size( )
457+ ) ;
441458 return Err ( AppError :: UnprocessableEntity (
442459 "subtree consistency proof failed" . to_owned ( ) ,
443460 ) ) ;
@@ -458,14 +475,6 @@ async fn sign_subtree(State(env): State<Env>, body: Bytes) -> ApiResult<axum::re
458475// Helpers
459476// ---------------------------------------------------------------------------
460477
461- /// Maximum `sign-subtree` request body, enforced by the route's
462- /// [`DefaultBodyLimit`] layer. A well-formed request is a `subtree` range
463- /// line, a base64 hash line, up to 8 subtree cosignature lines (~3.3 KiB
464- /// each for ML-DSA-44), up to 63 base64 consistency-proof hash lines, and
465- /// a reference checkpoint of up to `signed_note::MAX_NOTE_SIZE` (1 MiB);
466- /// 1 MiB plus 64 KiB of headroom covers that.
467- const MAX_SIGN_SUBTREE_BODY_SIZE : usize = 1_024 * 1_024 + 64 * 1_024 ;
468-
469478/// Maximum `add-checkpoint` request body, enforced by the route's
470479/// [`DefaultBodyLimit`] layer. A well-formed request is an `old <N>`
471480/// line, up to 63 base64 hash lines, and a checkpoint note of up to
0 commit comments