Skip to content

Commit

Permalink
Merge pull request #289 from filecoin-project/anorth/tipset
Browse files Browse the repository at this point in the history
Spec for ordering block parent CIDs by ticket
  • Loading branch information
whyrusleeping authored Jun 12, 2019
2 parents bc112a5 + 69d5af8 commit 6841949
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 16 deletions.
9 changes: 5 additions & 4 deletions data-structures.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ type Block struct {
// Miner is the address of the miner actor that mined this block.
Miner Address

// Tickets are the winning ticket that were submitted with this block.
// Tickets is a chain (possibly singleton) of tickets ending with a winning ticket submitted with this block.
Tickets []Ticket

// ElectionProof is a signature over the final ticket that proves this miner
// is the leader at this round
ElectionProof Signature

// Parents is the set of parents this block was based on. Typically one,
// but can be several in the case where there were multiple winning ticket-
// Parents is an array of distinct CIDs of parents on which this block was based.
// Typically one, but can be several in the case where there were multiple winning ticket-
// holders for a round.
// The order of parent CIDs is not defined.
Parents []Cid

// ParentWeight is the aggregate chain weight of the parent set.
Expand All @@ -60,7 +61,7 @@ type Block struct {
MessageReceipts Cid

// The block Timestamp is used to enforce a form of block delay by honest miners.
// Unix time UTC timestamp stored as an unsigned integer
// Unix time UTC timestamp (in seconds) stored as an unsigned integer.
Timestamp Timestamp

// BlockSig is a signature over the hash of the entire block with the miners
Expand Down
2 changes: 2 additions & 0 deletions expected-consensus.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ All valid blocks generated in a round form a `TipSet` that participants will att

The first condition implies that all blocks in a TipSet were mined at the same height (remember that height refers to block height as opposed to ticket round). This rule is key to helping ensure that EC converges over time. While multiple new blocks can be mined in a round, subsequent blocks all mine off of a TipSet bringing these blocks together. The second rule means blocks in a TipSet are mined in a same round.

The blocks in a tipset have no defined order in representation. During state computation, blocks in a tipset are processed in order of block ticket, breaking ties with the block CID bytes.

Due to network propagation delay, it is possible for a miner in round N+1 to omit valid blocks mined at round N from their TipSet. This does not make the newly generated block invalid, it does however reduce its weight and chances of being part of the canonical chain in the protocol.

### Chain Weighting
Expand Down
7 changes: 4 additions & 3 deletions mining.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,8 @@ To create a block, the eligible miner must compute a few fields:

- `Tickets` - An array containing a new ticket, and, if applicable, any intermediary tickets generated to prove appropriate delay for any failed election attempts. See [ticket generation](./expected-consensus.md#ticket-generation).
- `ElectionProof` - A signature over the final ticket from the `Tickets` array proving. See [ticket generation](./expected-consensus.md#ticket-generation).
- `Timestamp` - A Unix Timestamp generated at block creation. We use an unsigned integer to represent a UTC timestamp. The Timestamp in the newly created block must satisfy the following conditions:
- the timestamp on the block is not in the future
- the timestamp on the block is at least BLOCK_DELAY * len(block.Tickets) higher than the latest of its parents, with BLOCK_DELAY taking on the same value as that needed to generate a valid VDF proof for a new Ticket (currently set to 30 seconds).
- `ParentWeight` - As described in [Chain Weighting](./expected-consensus.md#chain-weighting).
- `Parents` - the CIDs of the parent blocks.
- `ParentState` - Note that it will not end up in the newly generated block, but is necessary to compute to generate other fields. To compute this:
- Take the `ParentState` of one of the blocks in the chosen parent set (invariant: this is the same value for all blocks in a given parent set).
- For each block in the parent set, ordered by their tickets:
Expand All @@ -311,6 +309,9 @@ To create a block, the eligible miner must compute a few fields:
- `ReceiptsRoot` - To compute this:
- Apply the set of messages selected above to the parent state, collecting invocation receipts as this happens.
- Insert them into a Merkle Tree and take its root.
- `Timestamp` - A Unix Timestamp generated at block creation. We use an unsigned integer to represent a UTC timestamp (in seconds). The Timestamp in the newly created block must satisfy the following conditions:
- the timestamp on the block is not in the future
- the timestamp on the block is at least BLOCK_DELAY * len(block.Tickets) higher than the latest of its parents, with BLOCK_DELAY taking on the same value as that needed to generate a valid VDF proof for a new Ticket (currently set to 30 seconds).
- `BLSAggregate` - The aggregated signatures of all messages in the block that used BLS signing.
- `BlockSig` - A signature with the miner's private key (must also match the ticket signature) over the entire block. This is to ensure that nobody tampers with the block after it propagates to the network, since unlike normal PoW blockchains, a winning ticket is found independently of block generation.

Expand Down
2 changes: 1 addition & 1 deletion sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ In this mode of operation a filecoin node should not mine or send messages as it

## Caught Up Mode

A filecoin node syncs in `caught up` mode after completing `syncing` mode. A node stays in this mode until it is shut down. New block cids are gossiped from the network through the hello protocol or the network's [block pubsub protocol](data-propagation.md#block-propagation). A node also obtains new block cids coming from its own successfully mined blocks. These cids are input to the `caught up` syncing protocol. If these cids belong to a TipSet already in the store then they are already synced and the syncing protocol finishes. If not the syncing protocol resolves the TipSet corresponding to the input cids. It checks that this TipSet is not in its badTipSet cache, and that this TipSet is not too far back in the chain using the consensus `Punctual` method. It then resolves the parent TipSet by reading off the parent cids in the header of any block of the TipSet. The above procedure repeats until either an error is found or the store contains the next TipSet. In the case of an error bad TipSets and their children not already in the bad TipSet cache are added to the cache before the call to `collectTipSetCaughtUp` returns.
A filecoin node syncs in `caught up` mode after completing `syncing` mode. A node stays in this mode until it is shut down. New block cids are gossiped from the network through the hello protocol or the network's [block pubsub protocol](data-propagation.md#block-propagation). A node also obtains new block cids coming from its own successfully mined blocks. These cids are input to the `caught up` syncing protocol. If these cids belong to a TipSet already in the store then they are already synced and the syncing protocol finishes. If not the syncing protocol resolves the TipSet corresponding to the input cids. It checks that this TipSet is not in its badTipSet cache, and that this TipSet is not too far back in the chain using the consensus `Punctual` method, nor too far ahead (TODO: reference finality number). It then resolves the parent TipSet by reading off the parent cids in the header of any block of the TipSet. The above procedure repeats until either an error is found or the store contains the next TipSet. In the case of an error bad TipSets and their children not already in the bad TipSet cache are added to the cache before the call to `collectTipSetCaughtUp` returns.

After collecting a chain up to an ancestor TipSet that was previously synced to the store the syncing protocol checks each TipSet of the new chain for validity one by one. When the filecoin network runs Expected Consensus, or any other multiple parents consensus protocol, the syncing protocol must consider not only the TipSets in the new chain but also possible new-heaviest TipSets that are the union of TipSets in the new chain and TipSets already in the store. In the case of Expected Consensus there is at most one such TipSet: the TipSet made up of the union of the first new TipSet in the new chain being synced and the largest TipSet with the same parents kept in the store.

Expand Down
26 changes: 18 additions & 8 deletions validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,23 @@

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](data-propagation.md) document.

For every block received, the node must validate it before executing it or passing it on. Before a node can validate a block, it first must ensure the block is structurally correct by decoding it (see [block](data-structures.md#block)) and ensuring that no field contains any illegal values. After that the node must check the signature of the block, then moves on to validate the block itself.
Validation is split into two stages, syntactic and semantic. The syntactic stage may be validated without reference to additional data (see [block](data-structures.md#block)). The semantic stage requires access to the chain which the block extends.

A valid block:
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.

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


A semantically valid block:

- must only have valid parents in the tipset, meaning
- that each parent itself must be a valid block
Expand All @@ -21,9 +35,5 @@ A valid block:


{{% notice info %}}
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. Blocks a certain distance from the current chain height may be dropped (exact number TBD, but blocks that havent been included after several days may be purged).
{{% /notice %}}

{{% notice info %}}
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.
{{% /notice %}}
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.
{{% /notice %}}

0 comments on commit 6841949

Please sign in to comment.