## Mortal Transactions in Substrate In Substrate, **mortal transactions** are valid only within a limited block range, enforced by the [`CheckMortality` ](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/frame/system/src/extensions/check_mortality.rs#L39) [**TransactionExtension**](https://github.com/paritytech/polkadot-sdk/blob/5072bf9b93dc1c9dff0161ab6efe2799036045e9/substrate/primitives/runtime/src/traits/transaction_extension/mod.rs#L230), which encodes the transaction’s era to specify its validity window. This little note explains implementation details of this feature. ### CheckMortality and Era The [era](https://github.com/paritytech/polkadot-sdk/blob/5072bf9b93dc1c9dff0161ab6efe2799036045e9/substrate/primitives/runtime/src/generic/era.rs#L31-L48) (and no, it is not a BABE era) is explicitly included in the transaction data (as [`CheckMortality`](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/frame/system/src/extensions/check_mortality.rs#L39) transaction extension). The `Era` is compactly encoded as a `(period, phase)` pair, which is a more size-efficient alternative to including a full block hash and still allows the runtime to deterministically reconstruct the birth block hash. Although the birth block hash is **not part of the transaction body**, it is included in the signed payload — the data that the signer signs — ensuring the signature is tied to a specific birth block. `subxt` is including the birth block hash [here](https://github.com/paritytech/subxt/blob/307872927116c557a849acad10c9826a31d9e2c5/core/src/config/transaction_extensions.rs#L325-L336). During validation, the runtime retrieves the birth block hash by calling the [`implicit` method](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/frame/system/src/extensions/check_mortality.rs#L64-L72) of the `CheckMortality` transaction extension. This method uses the era information to obtain the birth block hash needed to reconstruct the signed payload and verify the signature. ### Signature Verification and Era Validity If a transaction is submitted outside its valid era window, the [`implicit` method](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/frame/system/src/extensions/check_mortality.rs#L64-L72) reconstructs the birth block hash based on current context, which will differ from the one originally signed. This causes the signature verification to fail. Consequently, the transaction is rejected due to an invalid signature ([`InvalidTransaction::BadProof`](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/primitives/runtime/src/transaction_validity.rs#L50-L59)) rather than an explicit rejection by [`CheckMortality::validate`](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/frame/system/src/extensions/check_mortality.rs#L87-L109). ### BlockHashCount and Missing Birth Block Hashes Substrate nodes retain block hashes for only the last [`BlockHashCount`](https://github.com/paritytech/polkadot-sdk/blob/5072bf9b93dc1c9dff0161ab6efe2799036045e9/substrate/frame/system/src/lib.rs#L466-L468) blocks. A truly **missing** birth block hash occurs only if the era’s period exceeds `BlockHashCount`, meaning the birth block is too far in the past. In such cases, the required hash is unavailable so the runtime returns an [`AncientBirthBlock`](https://github.com/paritytech/polkadot-sdk/blob/40a005033bc1b67344cc4ac5e594956b583780f3/substrate/primitives/runtime/src/transaction_validity.rs#L60-L69) error, indicating the transaction is too old to validate.