Just some general points about transaction mortality from my digging and understanding so far:
- The goal of mortality is to define when a transaction is valid from (must be some recent block hash/number) and roughly how many blocks it'll be valid for until it expires and can no longer be added to a block.
- There are two parts to mortality; first, the
Mortal variant containing a "phase" and "period" value), and second the "mortality checkpoint" (the block hash of the first block that the transaction is valid from).
Era is encoded into a compact 1 or 2 byte representation (for immortal or mortal respectively) and is a part of the "signed extra" details of the extrinsic. This compact encoding is important to save space in a block.
- The "mortality checkpoint" hash is a part of the signer payload; ie it's not a part of the extrinsic details, but the node must be able to reproduce it to verify the signature. The node uses the "phase" value to work out which block hash should be a part of the signer payload for verification.
With that in mind, let's get to the questions:
Era::mortal function takes two arguments,
current (both u64s).
current is the block number that you'd like the transaction to be valid from. This block number must point to the same block as the block hash provided in the "mortality checkpoint" signer payload argument. Probably it should be some recent block (ie fetching the latest finalized block for instance and using that block hash/number seems like a good default approach).
period is the number of blocks after this block that the transaction will be valid for. It should be a power of 2 in the range [4,65536] (the
Era::mortal function will make this be the case if the value you provide is not already). The reason for this rounding-to-power-of-two is, I think, so that it can be compressed (along with the internal "phase" value) into just 2 bytes.
These two values are what you really care about when defining mortality; from which block is the tx valid from and after which block does it expire.
If you're not using the
Era::manual(..) function (eg because an equivalent is not available in the language you're using), personally my approach would be to copy the logic of it out into your own function. Take care to also copy the logic for how the
Era is SCALE encoded and decoded, if that's not handled for you (see here).
Era::Mortal stores a
phase as u64s, and when being SCALE encoded or decoded, it mangles these into just 2 bytes.
period has already been described above.
phase is a value that a validator can use to work out which block hash it should expect in the signer payload in order to produce an identical signature to that which was given with the tx. See
Era::mortal() for how it's calculated.
The spec goes into more detail about the mortality phase and period: https://spec.polkadot.network/id-extrinsics#id-mortality