Validation
Validation of Blocks is one of the two primary consensus functions (the other being application). The two are closely intertwined: when a block is validated, each of its transactions is first validated, then applied to a "midstate," which tracks intra-block effects.
Blocks are validated against their parent State. The state is not altered. First, block-level checks are performed:
- Weight: The Block must not be too large (as measured by its binary encoding). Merkle proofs are excluded when calculating weight.
- Miner Payout: The miner payout must equal the Block reward plus any Transaction fees. (Unlike e.g. Bitcoin, fees in Sia are explicit.)
- Timestamp: The Block's timestamp must be later than the median timestamp of the prior 11 Blocks. (Note that nodes will also typically reject Blocks with timestamps more than 3 hours ahead of their local time, but this is technically not a consensus rule.)
- Proof of Work: The Block's ID must be lower than the current Work target, and its nonce must be a multiple of 1009.
- Commitment: The Block's commitment hash must match the actual data in the block.
Next, each Transaction is validated in the order it appears in the Block. These checks can be subdivided by type:
- Siacoins and Siafunds: Each Input must be unspent, mature, and present in the accumulator or created in a prior Transaction within the Block. Its Spend Policy must be satisfied, typically by an Ed25519 signature. The total value of the inputs must equal the total value of the outputs (including regular outputs, file contracts, and miner fees).
- File Contracts: Each File Contract must have proof and expiration heights that are in the future, non-zero total value, a missed host payout and total collateral not exceeding the valid host payout, and must have valid signatures from the renter and host. Revisions must reference an unresolved contract present in the accumulator, must occur prior to the proof height, must not lower the revision number, must not modify the total payout value or collateral, and must have valid signatures. Resolutions come in three different flavors, but all must reference an unresolved contract present in the accumulator. Renewals may occur at any height, but must not misrepresent the total contract value or "rollover" excessive value, and their new contract must satisfy all the usual rules. Storage proofs must occur after the proof height and before the expiration height, must reference the proper ancestor block in the accumulator, and must contain a valid Merkle proof for the correct leaf of contract data. Lastly, Expirations must occur after the expiration height.
- Attestations: Each Attestation must have a non-empty key and a valid signature.
- Foundation Subsidy Updates: If a new Foundation address is specified, the transaction must prove ownership of the current address by spending one or more of its inputs.
In v1
As v1 nodes could only maintain one State at a time, fully validating a Block with a different parent State required reverting and applying all Blocks between it and the current State. This is an expensive operation; consequently, incoming orphan Blocks were first partially validated, and full validation was only performed in tandem with application during the reorg process.
Like most non-Utreexo blockchains, v1 performed validation while simultaneously mutating the database. This meant that validation could only be performed against the current state, and doing so required an exclusive lock on the database. If validation failed at any point, the database transaction would be rolled back. In contrast, v2 validation and application require no I/O at all, and many instances can occur simultaneously on different states.