Skip to content

Keep the received log per sender epoch#6604

Open
afck wants to merge 6 commits into
afck/vouch-referenced-blocksfrom
afck/received-log-per-epoch
Open

Keep the received log per sender epoch#6604
afck wants to merge 6 commits into
afck/vouch-referenced-blocksfrom
afck/received-log-per-epoch

Conversation

@afck

@afck afck commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Motivation

Validators keep every chain's received log forever, including entries that point at certificates from revoked epochs — which clients cannot verify on their own anymore. The log can't simply be truncated: clients track their position in it by index, so removing entries would shift every index behind them.

Proposal

Partition the received log by the epoch of the sender's certificate, so a revoked epoch's log can be dropped wholesale, and its client-side tracker with it. Validators prune revoked epochs when a client asks for a live epoch's log. Clients keep one tracker per validator and epoch, and request all live epochs in a single query, so a network with many live epochs doesn't pay for one round trip per epoch.

Since a sync then only sees live epochs' entries, an undelivered message from a pruned epoch could otherwise block the messages behind it forever. The client therefore processes the lowest listed block together with its sending ancestors, which re-certifies the pruned-epoch message through the links introduced in the previous PR.

Test Plan

CI, plus unit tests covering per-epoch log serving and pruning, the batched multi-epoch query, and a regression test for bulk-syncing across a revoked epoch.

Release Plan

  • Backporting is not possible but we may want to deploy a new devnet and release a new
    SDK soon.

Links

afck added 5 commits July 13, 2026 10:54
Partition ChainStateView::received_log by the epoch of the sender
block's certificate, and key received_certificate_trackers by validator
and epoch. Cross-chain updates already carry each bundle's epoch, so the
receiving worker files every entry under the epoch that certified it.

Clients now query the log per epoch (ReceivedLogQuery { epoch, skip }),
iterating exactly the live epochs: revocation is monotone, so these are
the epochs from the lowest unrevoked one up to the current one. Entries
of revoked epochs are useless to clients — the certificates they point
to can no longer be verified on their own, and blocks that still matter
are re-certified via previous_block_hash / previous_message_blocks links
— so validators drop a revoked epoch's log wholesale the next time a
client asks for a live epoch's log on that chain.

Also remove the unused count_received_log field from ChainInfo.
Use CustomCollectionView with a big-endian CustomSerialize impl for
Epoch, so the received log's per-epoch entries are stored in numeric
epoch order. Pruning then walks the stored epochs below the lowest
requested one from newest to oldest and stops at the first revoked
epoch: revocation is monotone, so everything below it is pruned without
further checks.

Replace the per-epoch received-log queries with a single batched query:
the client names all live epochs and their tracker offsets at once, and
the validator serves them in ascending epoch order under one total
entry bound per response. If the bound cuts an epoch's log short, the
client repeats the request with advanced offsets.

Turn received_certificate_trackers from a register holding one growing
map blob into a MapView keyed by (validator, epoch): updates only touch
the changed keys, and entries for revoked epochs — whose logs are
pruned and never queried again — are removed whenever the trackers are
updated. The field is node-local synchronization bookkeeping, so it is
no longer exposed via GraphQL.
A receiver syncing via the received log only sees live epochs' entries, but a
sender block from a revoked epoch may still be undelivered. Process the lowest
listed block together with its sending ancestors, so that the pruned-epoch
message is re-certified and delivered; otherwise the newer messages could never
be scheduled behind the missing one.
Key the pruning off the highest revoked epoch below the request, and drop the
now-redundant single-epoch query helper.
Comment thread linera-chain/src/chain.rs Outdated
Comment thread linera-chain/src/chain.rs Outdated
/// per sender epoch. Node-local synchronization bookkeeping, not exposed via
/// GraphQL.
#[cfg_attr(with_graphql, graphql(skip))]
pub received_certificate_trackers: MapView<C, (ValidatorPublicKey, Epoch), u64>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be MapView<C, ValidatorPublicKey, Vec<(Epoch, u64)>> to spare DB keys?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d1e9680.

But note that this field is only nonempty on the client side. Not sure how important it is to save DB keys there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants