Log Lifecycle

May 15, 2025 ยท View on GitHub

Log lifecycle is a useful concept for outlining expected modes the log can be in, and state transitions between these states. The lifecycle states outlined below exist either as explicit API constructs or as internal states, but there is no explicit state stored with the log data. The requirements for each state are documented, and the log operator takes responsibility to ensure that they only migrate between these states in the supported directions.

Terminology

The definitions below will use terms that we'll define here:

  • pending: an entry which has been submitted to the log and durably assigned a sequence number, but which has not yet been integrated.
  • integrated: a sequenced entry that has been included in the Merkle tree, and a checkpoint committing to it has been created.

Modes

Appender

The purpose of this mode is to allow entries to be assigned indices by, and integrated into, the log.

This is the "normal" state of most active logs, and is characterized by the writer personality using only the tessera.NewAppender lifecycle API.

In this mode, storage drivers:

  • durably assign and return sequence numbers for entries passed via the Add method on the Appender struct.
  • integrate entries with sequence numbers into the tree, possibly asynchronously.
  • periodically publish a new signed checkpoint file which commits to the contents of the tree.

This state can start from an empty tree, or from the Quiescent state, in which case there can be any number of entries already in the tree, but they must all be integrated.

The only valid transition outwards is to Quiescent, and the operator should ensure that new entries are not being accepted and all pending entries have been integrated before transitioning.

Migration

This mode is used to "import" tlog-tiles (or static-ct) compliant logs into a Tessera instance. The most common use case for this mode is migrating a log you operate between different supported Tessera infrastructure.

This state must start from an empty tree. It is characterized by the personality that uses only the tessera.NewMigrationTarget lifecycle API.

In this mode, the lifecycle struct will copy entry bundle resources from the source log into the target log, and locally re-create the merkle tree which commits to them. The resulting root hash should match the root hash of the source log at the same tree size.

Note

This lifecycle mode does not, by design, create or publish checkpoint files.

For logs being migrated between infrastructure, it is of paramount importance that only one of two logs is canonical at any given time in order to avoid inadvertently creating a fork. Consequently, Tessera will only create a new checkpoint file once the operator has completed the migration of the source data into the target log, verified its correctness, and manually switched over to Appender mode on the target log.

The only valid transition outwards is to Quiescent, and the operator should ensure that the migration operation has completed successfully before transitioning.

Quiescent

The purpose of this conceptual mode is to provide a safe intermediate state where the tree and all associated metadata is up-to-date and self-consistent.

This state may be considered as terminal, e.g. if the log is being frozen or retired.

This state requires Migration or Appender first.

No calls which can modify state should be made while in this mode.

The only valid transitions are to Appending (e.g. when a log migration is complete and the log should become operational in its new location), or Deleted.

Deleted

Each storage implementation will define instructions for deleting the contents of the log when no longer required. It can only be reached from the Quiescent state.

The concept of a soft-delete is not supported by Tessera, though the deployer may be able to realize this via their own infrastructure (e.g. by deleting URL mappings to the log handlers).

Lifecycle in Trillian v1

This lifecycle proposal was inspired by Trillian v1, but simplified as much as possible. For comparative purposes, the states possible in Trillian are documented below.

Using Trillian log TreeState and TreeType as inspiration, the largest conceivable lifecycle is:

  • No log / unknown
  • Empty log
  • Pre-ordered
  • Active
  • Draining (this is the only state that allows a back-transition. This can move back to Active)
  • Frozen
  • No log (deleted)