Expiry and timestamps
Every ZooBC transaction carries the moment it was made, in Unix seconds, inside its signed bytes. That timestamp opens a validity window: a block may include the transaction only within the window, and after it the transaction is dead and must be signed again. The window protects the signer. A payment that could not get into a block at a busy moment does not linger for days and then surprise them; it simply expires, and they can decide again.
The default window: one hour
By default a block may include a transaction until 3,600 seconds after its timestamp: one hour, or 240 blocks at one block every 15 seconds. After that, nodes refuse it with a message that ends "...sign it again".
The window also has a front edge. A transaction dated more than 3,600 seconds in the future is refused too, with a hint to check the signer's clock. This catches a device whose clock is wrong.
Choosing the window: version 3
A version-3 transaction carries a 4-byte expiry field, right after the fee and the survival field, and states its own window in seconds:
- 0 means the default hour;
- a smaller value shortens the window, for a payment that must happen soon or not at all;
- the largest allowed value is 86,400 seconds, one day; a larger value is refused.
A version 1 or 2 transaction has no expiry field, and one that states an expiry anyway is refused. Whatever the version, the limit of one hour into the future still applies.
A longer window helps when a signature takes time to collect: on a hardware wallet, or among the participants of a multisignature account.
How pools and chains keep up
Two companion rules make the day-long window safe:
- a node's transaction pool keeps each transaction for its own stated window;
- every chain keeps transaction ids for at least 25 hours: the longest window plus the one-hour tolerance into the future.
Since a node refuses an id it has already confirmed (see signing a transaction), a transaction can never be replayed while it is still valid.
Time in blocks
Blocks are checked against the same windows, so every node reaches the same verdict:
- a block whose timestamp is past a transaction's timestamp plus its window is invalid;
- so is a block that carries a transaction dated more than 3,600 seconds after the block.
Some settlements happen by themselves, block by block: Escrow deadlines, the completion of liquid payments (streams), scheduled transfers falling due, the expiry of orders resting on a market and the phases of the fee vote. These read the previous block's timestamp, not the block's own. A producer therefore cannot stamp its block a little ahead of time to pull a payout into it.
How blocks are spaced in time is explained in blocks and time.