linera-io / linera-protocol

Main repository for the Linera protocol
Apache License 2.0
826 stars 142 forks source link

Remaining incoming messages are automatically bounced when a chain is closed. #1653

Closed afck closed 8 months ago

afck commented 8 months ago

Also required for to https://github.com/linera-io/linera-protocol/issues/305.

afck commented 8 months ago

Design

Say chain C was closed at height hc. Chain A, at height ha later sends message m to C.

A's outbox for C now contains an entry ha, and a cross-chain message goes to the worker responsible for C.

~Proposal 1~

C is considered to have sent a SystemMessage::ChainClosed(BlockHeight) to all other chains at height hc; the argument is the lowest next expected block height from the recipient of that message, i.e. in A's case something ≤ ha. However, this message is treated specially, and only actually delivered to those chains that send a message to C that was not received at any height < hc (i.e. either at hc or not at all).

C's worker finds that C has been closed, and C's outbox for receiver A doesn't have an entry at height ≥ hc. So it puts hc into it; it does not put anything in C's inbox. When it sends the outgoing messages for A, it finds that entry and sends a cross-chain message with ChainClosed.

When A's worker receives that, it sets a closed flag in its own outbox for C, and takes all remaining messages from heights ≥ ha (and all future messages instead of putting them into the outbox); in this example m. It puts them into its own inbox from C, as "bounced".

In Event, height and index are replaced by a single cursor field. The Cursor becomes an enum:

enum Cursor {
    /// The other chain is active; the `height` and `index` refer to the other chain.
    Active { height: BlockHeight, index: u32 },
    /// The other chain has been closed; `height` and `index` refer to our chain.
    /// This is only used for bounced messages that were not received before the chain
    /// was closed. All `Closed` values are considered to be greater than `Active` values.
    Closed { height: BlockHeight, index: u32 },
}

If we eventually fully purge (or archive) the chain state, we'd also remove C's outbox from storage, so this would no longer work, and messages would fail to bounce. That may be okay, if we make the client handle bounced messages from closed chains with sufficient care: E.g. if we purge chains two weeks after closing, clients should never propose fast blocks that receive bounced messages older than one week from closed chains.

~Proposal 2~

Chains cannot be fully closed immediately, only handed over to the validators. The validators will keep adding blocks bouncing all messages in the future, for some period. (Like two weeks?)

This requires fewer exceptions in the message and inbox/outbox logic, but creates much more work for the validators. The purging issue is the same as in proposal 1.

afck commented 8 months ago

As discussed, we will change what it means to close a chain instead:

The owners are not removed; instead, a closed flag is set that disallows all operations, and only allows bouncing (but not accepting) messages.