Block Validation
In order to ensure they are always on the correct latest state of the chain a filecoin full node must accept and process blocks continuously. Blocks are propagated was described in the Data Propagation document.
Validation is split into two stages, syntactic and semantic. The syntactic stage may be validated without reference to additional data (see block). The semantic stage requires access to the chain which the block extends.
A node must decode and perform syntactic validation for every block received before passing it on (e.g. in a lipbp2p pubsub validator). A node must perform semantic validation before accepting the block as an extension to its chain.
Syntactical Validation
A syntactically valid block:
- must include a well-formed miner address
- must include at least one well-formed ticket, and if more they form a valid ticket chain
- must include an election proof which is a valid signature by the miner address of the final ticket
- must include at least one parent CID
- must include a positive parent weight
- must include a positive height
- must include well-formed state root, messages, and receipts CIDs
- must include a timestamp not in the future
Semantical Validation
A semantically valid block:
- must be from a valid miner, i.e. has not been slashed
- must only have valid parents in the tipset, meaning
- that each parent itself must be a valid block
- all parents must be at same height
- must have a valid ticket:
- the ticket must be the winning ticket
- the ticket must be generated from the smallest ticket in the parent tipset
- all tickets in the ticket array must have been generated by the same miner
- if it includes intermediary losing tickets in the ticket array, the node must confirm that each ticket correctly generates the next in the array
- must have a valid timestamp, meaning
- must be later than the earliest parent block time plus appreopriate delay, which is BLOCK_DELAY (30s by default) * len(blk.Tickets). see BLock Validation
- must only have valid state transitions:
- all messages in the block must be valid
- the execution of each message, in the order they are in the block, must produce a receipt matching the corresponding one in the receipt set of the block, see the state machine spec.
- the resulting state root after all messages are applied, must match the one in the block
Once the block passes validation, it must be added to the local datastore, regardless whether it is understood as the best tip at this point. Future blocks from other miners may be mined on top of it and in that case we will want to have it around to avoid refetching.
To make certain validation checks simpler, blocks should be indexed by height and by parent set. That way sets of blocks with a given height and common parents may be quickly queried. It may also be useful to compute and cache the resultant aggregate state of blocks in these sets, this saves extra state computation when checking which state root to start a block at when it has multiple parents.
Basic check
clarify which of these checks are needed in order to be allowed to validate and propagate a block. This is probably a sub-set of the above mentioned - and thus this paragraph might be moved there - that should be reasonably quick to check and hard to spoof or get around.