You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Enhance aggregator support for signatures when not ready #3409
The aggregator is not properly handling the reception of single signatures when it is not ready to sign (in particular when it is blocked). In that case, a long error message is logged which prevents their readability and exploitation during debugging.
What
Enhanced handling of incoming signatures when the aggregator is not ready.
How
Add a new service SingleSignatureRegistrationGate in the aggregator
Add a new get_status(&self)->SingleSignatureRegistrationStatus method and a SingleSignatureRegistrationStatus enum
The gate is closed when the state machine is in the Blocked state
The gate is opened during the Idle state
The /register-signature route returns a 503 error if the gate is closed, and is not modified otherwise
I would like to take this one, but the re-read against main (cf1bb36) changes one of the premises, so I would rather confirm the direction before writing any code.
The long error message is not what a blocked aggregator produces today.BufferedCertifierService::register_single_signature intercepts CertifierServiceError::NotFound for an authenticated signature and stores it (buffered_certifier.rs:103-115), so when the state machine is Blocked and no open message exists for the signed entity type, the route answers 202 Accepted via SignatureRegistrationStatus::Buffered (signatures_routes.rs:147). The branch that logs "full_payload" => #?payload and answers 500 (signatures_routes.rs:133-136) is only reached for errors that are none of AlreadyCertified, Expired and NotFound.
Which means a gate answering 503 in the Blocked state is not a readability improvement: it replaces the buffering path. Single signatures that are stored now and registered later, when the open message is created, would be rejected instead, and signers would have to retry. That is a behaviour change on the signer side, and openapi.current.yaml would need a new 503 response for /register-signatures (the file currently lists 201, 202, 400, 404, 410 and a default).
Two things I would rather not decide on my own:
Where does the gate read the state?AggregatorRuntime owns state privately (state_machine.rs:107) and is moved into a spawned task at serve_command.rs:164-169, before the routes are built at :183, so RouterState has no handle on it today. Publishing the state into a shared cell on every cycle, and moving the gate into the certifier decorator, are both viable and they land in different parts of the codebase.
Is the gate closed in Ready and Signing too? The checklist names Blocked as closed and Idle as open, and says nothing about the other two states. I would read "closed only when blocked" as the intent, but the window between Ready and the creation of the open message is exactly the case buffering exists for.
If the direction is right, I will keep it to the gate service, the route, the openapi entry and the tests, as separate small pieces.
@jpraynaud and @hjeljeli32 asked me to keep to one issue at a time, and #3470 is still in flight with #3566 open and awaiting review. I asked a question here rather than starting, and nobody has needed the answer urgently enough to reply, so I will not hold the slot.
For whoever picks this up, the finding from my comment above is the useful part, and it is still true on main at cf1bb36ed: the premise in the issue is out of date. BufferedCertifierService::register_single_signature intercepts CertifierServiceError::NotFound for an authenticated signature and buffers it (buffered_certifier.rs:103-115), so a Blocked aggregator with no open message for the signed entity type answers 202 Accepted via SignatureRegistrationStatus::Buffered (signatures_routes.rs:147). The 500 with "full_payload" => #?payload that the issue describes is a different path. Worth confirming which behaviour is actually wanted before building the gate.
Activity
HusseinAdeiza commentedon Sep 27, 2026
I would like to take this one, but the re-read against
main(cf1bb36) changes one of the premises, so I would rather confirm the direction before writing any code.The long error message is not what a blocked aggregator produces today.
BufferedCertifierService::register_single_signatureinterceptsCertifierServiceError::NotFoundfor an authenticated signature and stores it (buffered_certifier.rs:103-115), so when the state machine isBlockedand no open message exists for the signed entity type, the route answers202 AcceptedviaSignatureRegistrationStatus::Buffered(signatures_routes.rs:147). The branch that logs"full_payload" => #?payloadand answers 500 (signatures_routes.rs:133-136) is only reached for errors that are none ofAlreadyCertified,ExpiredandNotFound.Which means a gate answering 503 in the
Blockedstate is not a readability improvement: it replaces the buffering path. Single signatures that are stored now and registered later, when the open message is created, would be rejected instead, and signers would have to retry. That is a behaviour change on the signer side, andopenapi.current.yamlwould need a new 503 response for/register-signatures(the file currently lists 201, 202, 400, 404, 410 and a default).Two things I would rather not decide on my own:
Where does the gate read the state?
AggregatorRuntimeownsstateprivately (state_machine.rs:107) and is moved into a spawned task atserve_command.rs:164-169, before the routes are built at:183, soRouterStatehas no handle on it today. Publishing the state into a shared cell on every cycle, and moving the gate into the certifier decorator, are both viable and they land in different parts of the codebase.Is the gate closed in
ReadyandSigningtoo? The checklist namesBlockedas closed andIdleas open, and says nothing about the other two states. I would read "closed only when blocked" as the intent, but the window betweenReadyand the creation of the open message is exactly the case buffering exists for.If the direction is right, I will keep it to the gate service, the route, the openapi entry and the tests, as separate small pieces.
HusseinAdeiza commentedon Sep 28, 2026
Releasing this one, no code started.
@jpraynaud and @hjeljeli32 asked me to keep to one issue at a time, and #3470 is still in flight with #3566 open and awaiting review. I asked a question here rather than starting, and nobody has needed the answer urgently enough to reply, so I will not hold the slot.
For whoever picks this up, the finding from my comment above is the useful part, and it is still true on
mainatcf1bb36ed: the premise in the issue is out of date.BufferedCertifierService::register_single_signatureinterceptsCertifierServiceError::NotFoundfor an authenticated signature and buffers it (buffered_certifier.rs:103-115), so aBlockedaggregator with no open message for the signed entity type answers202 AcceptedviaSignatureRegistrationStatus::Buffered(signatures_routes.rs:147). The 500 with"full_payload" => #?payloadthat the issue describes is a different path. Worth confirming which behaviour is actually wanted before building the gate.Happy to re-claim once #3566 lands.