From 5a7d837cf08c7505b987d13f9207ad04644ec91f Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:43:56 +0100 Subject: [PATCH 01/33] First draft of F3 --- FIPS/fip-xxxx.md | 730 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 730 insertions(+) create mode 100644 FIPS/fip-xxxx.md diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md new file mode 100644 index 00000000..bd9ddb03 --- /dev/null +++ b/FIPS/fip-xxxx.md @@ -0,0 +1,730 @@ +--- +fip: "" +title: Fast Finality in Filecoin +author: Jie Hou (@mb1896), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) +discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 +status: Draft +type: Technical +category: Core +created: 2023-12-18 +--- + +# Fast Finality in Filecoin + +## Simple Summary + +Filecoin clients currently consider blocks irreversible after 900 epochs, hindering applications requiring low latency. This FIP specifies Fast Finality in Filecoin (F3), extending the protocol with a new component that reduces finalization time from 7.5 hours to tens of seconds. + + +## Abstract + +The current Filecoin consensus mechanism only provides probabilistic finality. To simplify client implementations and provide some form of determinism, the protocol also includes a soft finality threshold, whereby miners at round _N_ reject all blocks that fork off before _N-900_. This finalization delay of 900 epochs (7.5 hours) hinders user experience and limits applications built on Filecoin. + +We specify a mechanism for fast finality with the F3 component. F3 is expected to finalize tipsets within tens of seconds during regular network operation, compared to the current 900-epoch finalization delay. It does so by leveraging GossiPBFT, an optimally resilient partially synchronous BFT consensus protocol, which runs in parallel with the current protocol, taking EC tipsets as input and providing finalized prefixes as output. EC’s fork choice rule is modified never to select away from the F3-finalized chain. + + +## Change Motivation + +* The long time to finality on Filecoin mainnet restricts or severely affects applications built on Filecoin (e.g., IPC, FVM, Axelar, Wormhole, Glif, …). +* Even though applications on Filecoin can set a lower finalization time than the built-in 900 epochs, delayed finalization for important transactions will require tens of minutes with a longest-chain protocol like Filecoin’s Expected Consensus (EC). +* Long finalization times also affect exchanges, by imposing a long confirmation period (often more than 1 hour) for users managing their FIL assets, and bridges, which face extended wait times for asset transfers. +* Bridging to other systems is not currently fast, safe, and verifiable. + + +## Specification + + +### Background + +[Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. + +![](https://hackmd.io/_uploads/Skmdqq6Ip.png) + +Two or more tipsets of the same epoch with different parent tipsets (like tipsets _C_ and _C'_ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant _p1_ is not (yet) aware of tipset _D_, it would consider _C_ the heaviest tipset with the canonical chain _[G A B C]_. Another participant _p2_ aware of tipset _D_ will consider _[G A C’ D]_ to be the canonical chain. Once _p1_ becomes aware of tipset _D_, it will update its canonical chain to _[G A C’ D]_ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. + +In EC and, generally, longest-chain protocols, the probability of a path from some tipset _h_ to the genesis tipset becoming finalized increases with the number of descendant tipsets of _h_. This happens because the weight of the heaviest chain increases the fastest, as the tipsets with the most new blocks are appended to it (assuming that honest participants form a majority). In the particular case of EC, in each epoch, most created blocks are expected to come from honest participants and thus extend the heaviest chain. Consequently, it becomes progressively harder for a different path to overcome that weight. Over time, the probability of a tipset never undergoing a reorganization becomes high enough that the tipset is considered final for all practical purposes. In the Filecoin network, a tipset that is part of the heaviest chain is considered final after 900 epochs (or, equivalently, 7.5 hours) from its proposal. + + +### F3 Overview and Interaction with EC + +We propose implementing fast finality in Filecoin by introducing an F3 component, which works alongside EC in Filecoin client nodes (participants). + +The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage that the SP has committed to the network. This information is maintained in a system actor called the _power table_. + +In short, each participant _p_ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds it input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration _i_ (corresponding to the i-th instance of F3): + +- **EC/F3 interface:** Participant _p_ feeds its current canonical chain _canonical_ and its previously F3-finalized chain, which we call the _baseChain_, to F3. The _baseChain_ defines the power table and seeds randomness used to configure the F3 instance, while _p_'s current canonical chain is the chain _p_ proposes to be finalized. Periodically, _p_ also feeds to F3 tipset updates from EC that extend _p_'s canonical chain as EC delivers these tipsets. +- **F3 consensus:** F3 establishes network-wide consensus on finalized tipsets and produces a _Proof of Finality (PoF)_ for a tipset finalized in instance _i_, _t(i)_. Every _PoF_ output by F3 is signed by ≥ ⅔ of the total QAP, i.e., a super-majority of the power table vouching that honest participants with more than ⅓ QAP consider tipset _t(i)_ final. +- **EC:** Participant _p_ updates its local EC chain and commits not to reorganize the finalized tipset _t(i)_, i.e., the tipset must stay in _p_'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). +- **F3 synchronization:** Participants disseminate information about finalized tipset _t(i)_ and its proof _PoF(i)_ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. + +![](https://hackmd.io/_uploads/r13SXiTU6.png) + +### F3 Adversarial Model + +Honest participants follow the protocol at all times. Byzantine participants deviate arbitrarily from the protocol. Rational participants deviate from the protocol to pursue a greater (expected) pay-off according to their utility function. We consider a Byzantine adversary able to control and orchestrate up to less than ⅓ QAP. + +We further adapt our protocols to align the actions of honest and rational participants by ensuring that rational participants never contribute to finalizing a chain they do not locally possess. Without this, If a participant _p_ were to finalize a chain it didn’t have, then _p_ would not be able to mine in EC until it retrieved the required blocks and thus, in the meantime, could not obtain the cryptoeconomic rewards that EC offers. To this end, F3 provides _EC incentive compatibility_. + +F3 and its implementation GossiPBFT provide additional robustness for strong adversaries that control more than ⅓ QAP, such as: + +* Censorship resistance against a coalition of rational participants trying to leak power, without providing firm guarantees. +* Resilience to long-range attacks by an adversary controlling up to less than ⅔ QAP of any old power table. + + +### Best-effort Broadcast and Gossipsub + +F3 uses GossipSub (like Filecoin EC) to disseminate protocol messages, implementing a broadcast channel among participants. We assume and model GossipSub to satisfy the following properties of the _best-effort broadcast primitive_ (denoted _BEBroadcast_ hereafter): + +* If _p_ and _p’_ are honest, then every message broadcast by _p_ is eventually delivered by _p’_. +* No message with sender _p_ is delivered unless it was previously broadcast by _p_. + + +### Partially Synchronous Model and Δ-Synchrony + +We say the system is _Δ-synchronous_ if the combined computation and communication delay between any two honest participants is smaller than _Δ_. We assume that, under _Δ_-synchrony, any message broadcast by an honest participant is delivered by every honest participant within a time bound of _Δ_. + +In practice, if GossipSub is used for _BEBroadcast_, _Δ_ is effectively the assumed upper bound on GossipSub latency (e.g., a few seconds). + +For termination, we assume a classical partially synchronous model with an unknown bound on communication delays among non-Byzantine participants. + + +### Properties of F3 + +F3 is not identical to classical consensus, however similar to it. In a nutshell, the reasons why EC and Filecoin should not rely on classical consensus properties (implemented by existing off-the-shelf BFT consensus protocol) for fast finality are twofold: EC incentive compatibility and resilience to Filecoin power leakage attacks in case of a strong adversary. We refer to the accompanying document [Appendix A: F3 requirements specific to Filecoin and EC](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.jg4hdeovc1zg) for more details. + +With this in mind, the F3 component interface and properties are given below. + +> **Interface and properties of F3 at participant p:** +> +> `F3.invoke (int i, chain canonical, chain baseChain)` **returns** (we say finalizes) `(int i, chain h, proof_of_finality PoF)` +> +> **Properties:** +> +> **Agreement.** If two honest participants finalize _(i,h,*)_ and _(i,h’,*)_, then _h_ = _h_’. +> +> **Validity.** If an honest participant finalizes _(i,h,*)_, then _h_ is a prefix of the canonical input chain of some honest participant _p’_ in instance _i_. +> +> **Proof of Finality.** If an honest participant finalizes _(i,h,PoF)_, then _PoF_ is signed by ⅔ QAP majority corresponding to the _PowerTable(baseChain)’_ input in instance _i_ of some honest participant _p’_. +> +> **Progress.** If the system is _Δ_-synchronous, i.e., +> * All honest participants can communicate within a known time bound _Δ_, and +> * no honest participants invokes _F3(i, *, *)_ later than _Δ_ after another participant invokes _F3(i, *, *)_, +> +> Let c be the heaviest common prefix of the inputs of all honest participants in instance _i_. Then, if an honest participant finalizes _(i,c’,*)_, _c is a prefix of c_’ with probability > 0.5. +> +> **Termination.** If the system is _Δ_-synchronous, every call to F3 eventually returns with probability _1_. +> +> **EC Incentive compatibility.** An honest participant never contributes to gathering ⅔ QAP (super-majority) of votes for a chain _c_ which its local EC instance did not already deliver unless it already observes evidence of such a super-majority for chain _c_. +> +> `F3.ECupdate (int i, chain c)`: Participant _p_ updates F3 instance _i_ with chain _c_, which its EC instance locally delivered (relevant to EC incentive compatibility) + +We later show the specific estimate chosen for _Δ_ to optimize termination (See [here](#Synchronization-of-Participants-in-the-Current-Instance)). + + +### Consensus Interface + +The GossiPBFT consensus protocol is the main dependency of the F3. We will treat GossiPBFT as a black box here and defer the explanation of its internals to the [respective section](#GossiPBFT-Consensus) of this FIP. For now, it suffices to say that it is a Byzantine fault-tolerant consensus protocol that provides the typical properties of (1) agreement (no two honest participants decide differently), (2) validity (the decided value must pass a validity predicate), and (3) termination (every honest participant eventually decides). + +We denote the invocation of a consensus instance from a participant as follows: + +``` +GossiPBFT(i, proposal, participants) → decision, PoF +``` + +A participant that invokes the _GossiPBFT()_ function starts a consensus instance identified by the sequence number _i_ and with an input value _proposal_. The _participants_ parameter is composed of the SPs that participate in this instance along with their respective individual weights (i.e., quality-adjusted power). The next section explains how the _participants_ are obtained from the power table. The invocation eventually returns a _decision_ value and a proof of finality _PoF_ that proves _decision_ is indeed the output of this consensus instance. In any invocation from F3, _decision_ is a finalized chain prefix in the form of a tipset. _PoF_ can be verified by using the _Verify()_ function that we explain below: + +``` +Verify(PoF, decision, participants) → boolean +``` + +This function uses the _PoF_ to verify that _decision_ was the output of some instance of consensus executed among the _participants_. + + +### Power Table and Consensus Participants + +As mentioned, the _power table_ is a system actor that maintains, among other things, the quality-adjusted power of each SP. Each tipset _t_ in the chain corresponds to a particular version of the power table denoted _PowerTable(t)_ that results from executing all messages in the chain from genesis to _t_. The participants of an instance of GossiPBFT are determined by the power table resulting from the tipset finalized by the previous instance. More rigorously, the input parameter _participants_ of an instance _i_ is obtained from _PowerTable(decisioni-1)_, where _decisioni-1_ is the tipset output by instance _i-1_. If _i_ is the first consensus instance, _decisioni-1_ is the genesis tipset. + +We assume that _PowerTable(t)_ ignores any unnecessary data in the power table and returns the set consisting of each participant's identity and weight. + + +### F3 Pseudocode + +We now present the pseudocode of the F3 algorithm: + +``` +// finalizedTipsets is a list of records with tipset and PoF fields representing +// all finalized tipsets with their respective proof of finality. + +// It is initialized with the genesis tipset by definition, which needs no proof. +finalizedTipsets[0].tipset ← genesis +finalizedTipsets[0].PoF ← nil + +i ← 1 +while True: +participants ← PowerTable(finalizedTipsets[i-1].tipset) +proposal ← ChainHead() +finalizedTipset, PoF ← GossiPBFT(i, proposal, participants) + finalizedTipsets[i].tipset ← finalizedTipset + finalizedTipsets[i].PoF ← PoF + i ← i + 1 +``` + +Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named _finalizedTipsets_. It contains one _finalizedTipsets[i]_ entry per consensus instance where _finalizedTipsets[i].tipset_ and _finalizedTipsets[i].PoF_ denote, respectively, the tipset and PoF output by consensus instance _i_. A participant considers a tipset finalized if it is included in _finalizedTipsets_ or is an ancestor of some tipset included in _finalizedTipsets_. + +The algorithm starts by initializing _finalizedTipsets[0]_ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration _i_ of the loop, it takes the following steps (see [this document](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit) for details): + +1. Obtain the set of participants of instance _i_ from the power table determined by the previously finalized tipset. +2. Call the _ChainHead()_ function that returns the head tipset of the locally observed chain constructed by EC and sets the _proposal_ variable to the returned value. We assume that such a function is available to the finalizer. +3. Execute the instance _i_ of GossiPBFT consensus. +4. Add the returned tipset from the consensus execution to the _finalizedTipsets_ list. + +To prevent useless instances of GossiPBFT deciding on the same _baseChain_ because of the lack of a new epoch that provides a new proposal, we make the _ChainHead()_ function blocking in that it does not return a proposal unless (i) the drand epoch value for the epoch immediately following the latest finalized tipset is received and (ii) the current chain head is different from the chain head of the finalized chain. + + +### Changes to EC: Fork Choice Rule + +EC needs to be modified to accommodate the finalization of tipsets by F3. **This is the only change to EC this FIP introduces.** + +The current EC fork-choice rule selects, from all the known tipsets, the tipset backed by the most weight. As the F3 component finalizes tipsets, the fork-choice rule must ensure that the heaviest finalized chain is always a prefix of the heaviest chain, preventing reorganizations of the already finalized chain. + +We achieve this by adjusting the definition of weight for a finalized prefix: the heaviest finalized chain is the one that **matches exactly the tipsets finalized by F3**, in that a tipset _T’_ that is a superset of finalized tipset _T_ in the same epoch is not heavier than _T_ itself, despite it being backed by more EC power. + +This redefinition of the heaviest chain is consistent with the abstract notion of the heaviest chain being backed by the most power because a finalized tipset has been backed by a super-majority of participants in GossiPBFT. In contrast, any non-finalized block in the same epoch is only backed in that epoch by the EC proposer. + +We illustrate the updated rule in the following figure, where blocks in blue are finalized blocks, and all blocks are assumed to be proposed by a proposer holding only one EC ticket (the weight of a chain is the number of blocks): + +![](https://hackmd.io/_uploads/SJumBiT8p.png) + +The current EC fork-choice rule would select the tipset _{D0, D1}_ as the head of the heaviest chain. However, the heaviest finalized tipset is _{C3}_, which is not an ancestor of _{D0, D1}_. Therefore, the new fork choice rule selects _{D3}_ as the head of the heaviest chain. The reason why _D4_ is not selected is that its parent tipset does not exactly match the finalized tipset _{C3}_, but a superset of it, i.e. _{C3, C4}_. + + +### Bootstrapping + +Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, _upgradeEpoch_, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the _upgradeEpoch_ minus the 900-epoch lookback as the head tipset of the first _baseChain_, which is assumed by design to be common to all participants. + + +### GossiPBFT Consensus + +This section provides the specification of GossiPBFT, the consensus protocol that is iteratively instantiated by the F3 loop and returns a decision (in the form of an F3-finalized chain) and a PoF per instance. + +GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the **final** decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent (see [main design document](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit) for details). + +GossiPBFT was designed with the Filecoin network in mind and presents a set of features that make it desirable in that context: + +* Participants can have different weights, which aligns with how storage providers have different amounts of storage committed to the network. A participant's weight in executing the protocol is proportional to their share of QAP. +* The protocol has optimal resilience, i.e., it tolerates a Byzantine adversary controlling up to less than ⅓ QAP. +* Unlike PBFT, HotStuff, Tendermint, and many other protocols in this space, GossiPBFT is a leaderless protocol. This property makes it resistant to denial of service attacks because no designated participant represents the weakest link. +* Low latency. During periods of synchrony and honest proposers, GossiPBFT will finish in three communication steps. We expect this to happen within tens of seconds. +* GossiPBFT has been tailored with Filecoin and open blockchains in mind, with strong resilience against censorship attacks and incentive compatibility for rational participants. +* GossiPBFT is tailored to using a broadcast communication primitive, GossipSub, which Filecoin already uses. +* GossipPBFT internal invariants, on which the protocol correctness is based, are very similar to those of the seminal PBFT protocol, making protocol correctness easier to establish. + + +#### Message format, signatures, and equivocation + +Messages include the following fields: __. As _Round_, _Evidence_, and _Ticket_ are fields that not all message types require, when not required by a message type, their default value is used (i.e. _0_, _AggregatedEvidence{0, []ECTipset{}, 0, 0, []byte{}, []byte{}}_, and _{}_, respectively). We refer to a _field_ of message _m_, with _m.field_: + +``` +type GossiPBFTMessage struct { + // ID of the sender/signer of this message (a miner actor) + Sender ActorID + // BLS Signature + Signature []bytes + // Enumeration of QUALITY, PREPARE, COMMIT, CONVERGE, DECIDE + MsgType int + // Chain of tipsets proposed/voted for finalization in this instance. + // Non-empty: the first entry is the base tipset finalized in instance-1 + Value []ECTipset + // GossiPBFT instance number + Instance int + // GossiPBFT round for this message + Round int + // Aggregated GossiPBFTMessages that justify this message + Evidence AggregatedEvidence + // GossiPBFT ticket (only for CONVERGE) + Ticket []byte +} + +type ECTipset struct { + Epoch int + Tipset CID // Or TipsetKey (concat of block header CIDs) + Weight BigInt + PowerTable CID // CID of a PowerTable +} + +// Table of nodes with power >0 and their public keys. +// This is expected to be calculated from the EC chain state and provided to GossiPBFT. +// In descending order to provide unique representation. +type PowerTable { + Entries []PowerTableEntry +} + +type PowerTableEntry { + ParticipantID ActorID + Power BigInt + Key BLSPublicKey +} + +// Aggregated list of GossiPBFT messages with the same instance, round and value. Used as evidence for justification of messages +type AggregatedEvidence { + // Enumeration of QUALITY, PREPARE, COMMIT, CONVERGE, DECIDE + MsgType int + // Chain of tipsets proposed/voted for finalisation in this instance. + // Non-empty: the first entry is the base tipset finalised in instance-1 + Value []ECTipset + // GossiPBFT instance number + Instance int + // GossiPBFT round + Round int + // Indexes in the base power table of the signers (bitset) + Signers []bytes + // BLS aggregate signature of signers + Signature []bytes +} + +``` + +All messages broadcast by a participant have their participant ID in the sender field and contain a digital signature by that participant _(m.Signature)_ over _(Instance || MsgType || Value || Round)_. The protocol assumes aggregatable signatures (e.g., BLS, Schnorr), resilient to [rogue public key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html) (see [Boneh, Drijvers, and Neven](https://eprint.iacr.org/2018/483.pdf) construction and [F3 Finality Decision Exchange Protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow) for more details). + +The receiver of a message only considers messages with valid signatures and discards all other messages as invalid. We sometimes omit the sender IDs and signatures in further descriptions for better readability. + +Two (or more) messages _m1_ and _m2_ are called _equivocating messages_ if _m1.Sender=m2.Sender AND m1.Instance=m2.Instance AND m1.Value ≠ m2.Value AND m1.MsgType=m2.MsgType AND (if applicable) m1.Round=m2.Round_. We call _m1.Sender_ an _equivocating sender_. + +A set of messages _M_ that does not contain equivocating messages is called _clean_. Participants discard all equivocating messages when forming clean sets. + + +#### Predicates and functions used in the protocol + +* `Power(p | P) ∈ [0, 1]` + * Returns the relative QAP of participant _p_ (or set of participants _P_) in EC, defined by the power table corresponding to _baseChain_. The returned value is a fraction of the total QAP of all participants in the power table. +* `isPrefix(a,b)` + * Returns _True_ if _a_ is a prefix of _b_. (Each chain is also a prefix of itself.) +* `StrongQuorum(prefix,M)` + * Where _M_ is a clean set of messages of the same type and the same round. + * Let _P_ be the set of participants who are senders of messages in _M_ such that their message contains a value with _prefix_ as a prefix. More precisely: + `Let P={p : ∃ m∈ M: m.sender=p AND isPrefix(prefix,m.value)}` + then the predicate returns _True_ iff _Power( P )>2/3_ +* `HasStrongQuorumValue(M)` + * Where _M_ is a clean set of messages of the same type and the same round + * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>2/3_. More precisely: + `HasStrongQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>2/3` +* `StrongQuorumValue(M)` + * Returns _v_ if _HasStrongQuorumValue(M)_ holds, nil otherwise. +* `HasWeakQuorumValue(M)` + * Where _M_ is a clean set of messages of the same type and the same round + * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>1/3_. More precisely: + `HasWeakQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>1/3` +* `WeakQuorumValue(M)` + * Returns _v_ if _HasWeakQuorumValue(M)_ holds, nil otherwise. +* `LowestTicketProposal(M)` + * Let _M_ be a clean set of CONVERGE messages for the same round. + * If _M = ∅_, the predicate returns _baseChain_. + * If _M ≠ ∅_, the predicate returns _m.value_, such that _m_ is the message in _M_ with the lowest ticket (_m.ticket_). +* `Aggregate(M)` + * Where _M_ is a clean set of messages of the same type _T_, round _r_, and instance _i_, with _v=StrongQuorumValue(M)≠nil_. + `Let M' ← {m ∈ M : m.value = StrongQuorumValue(M)}` + * Returns a tuple __ where _participants_ are all participants such that _m.sender ∈ M'_ (in some compact/compressed representation, i.e. a bitmask with optional run-length encoding) and _agg-sig_ is an aggregate signature (BLS) across all of those participants on _m.i||m.T||m.r||m.v_ for some _m ∈ M'_. + + +#### GossiPBFT pseudocode (main algorithm) + +We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per round (_QUALITY_/_CONVERGE_, _PREPARE_, _COMMIT_) and an additional step outside the round loop (DECIDE). The _Sender_, _Signature_, and _Instance_ fields are omitted from messages for better readability. See also the simplified [PlusCal/TLA+ specification](https://github.com/filecoin-project/f3/blob/main/PlusCal-TLA/GossiPBFT.tla). + +``` +F3(inputChain, baseChain) returns (chain, PoF): +1: round ← 0; +2: decideSent ← False; +3: proposal ← inputChain; \* holds what the participant locally believes should be a decision +4: timeout ← 2*Δ +5: ECCompatibleChains ← all prefixes of proposal, not lighter than baseChain +6: value ← proposal \* used to communicate the voted value to others (proposal or 丄) +7: evidence ← nil \* used to communicate optional evidence for the voted value + +8: while (not decideSent) { +9: if (round = 0) +10: BEBroadcast ; trigger (timeout) +11: collect a clean set M of valid QUALITY messages + until StrongQuorum(proposal, M) OR timeout expires +12: let C={prefix : IsPrefix(prefix,proposal) and StrongQuorum(prefix,M)} +13: if (C = ∅) +14: proposal ← baseChain \* no proposals of high-enough quality +15: else +16: proposal ← heaviest prefix ∈ C \* this becomes baseChain or sth heavier +17: value ← proposal + +18: if (round > 0): \* CONVERGE +19: ticket ← VRF(Randomness(baseChain) || round) +20: value ← proposal \* set local proposal as value in CONVERGE message +21: BEBroadcast ; trigger(timeout) +22: collect a clean set M of valid CONVERGE msgs from this round + until timeout expires +23: value ← LowestTicketProposal(M) \* leader election +24: if value ∈ ECCompatibleChains \* see also lines 54-57 +25: proposal ← value \* we sway proposal if the value is EC compatible +26: else +27: value ← 丄 \* vote for not deciding in this round + +28: BEBroadcast ; trigger(timeout) +29: collect a clean set M of valid msgs \* match PREPARE value against local proposal +until Power(M) > ⅔ OR timeout expires +30: if (Power(M)>⅔) \* strong quorum of PREPAREs for local proposal +31: value ← proposal \* vote for deciding proposal (COMMIT) +32: evidence ← Aggregate(M) \* strong quorum of PREPAREs is evidence +33: else +34: value ← 丄 \* vote for not deciding in this round +35: evidence ← nil + +36: BEBroadcast ; trigger(timeout) +37: collect a clean set M of valid COMMIT messages from this round +until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) + OR (timeout expires AND Power(M)>2/3) +38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide +39: BEBroadcast 0. + return False +If m.step ∈ {CONVERGE, COMMIT} AND | CONVERGE, COMMIT + NOT ValidEvidence(m) | must contain valid evidence. + return False +return True +``` + +The _ValidEvidence()_ predicate is defined below (for other definitions used below, see [Preliminaries](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.ygq5svj4e7ap)). Note that _QUALITY_, _PREPARE_ and _DECIDE_ messages do not need evidence. In fact, _DECIDE_ does not need any protocol-specific validation, since a weak quorum of _DECIDE_ with the same value is required to trigger any execution of the protocol. + +``` +ValidEvidence(m): + + +(m = | valid CONVERGE +AND (∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum + AND ((∀ m' ∈ M: m'.step = COMMIT AND m'.value = 丄) | of COMMIT msgs for 丄 + OR (∀ m' ∈ M: m'.step = PREPARE AND | or PREPARE msgs for + m'.value = m.value)) | CONVERGE value +AND (∀ m' ∈ M: m'.round = m.round-1) | from previous round + + +OR (m = | valid COMMIT + AND ((∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum + AND ∀ m' ∈ M: m'.step = PREPAR | of PREPARE messages + AND ∀ m' ∈ M: m'.round = m.round | from the same round + AND ∀ m' ∈ M: m'.value = m.value) | for the same value, or + OR (m.value = 丄)) | COMMIT is for 丄 with + | no evidence +``` + +### Evidence verification complexity +Note that during the validation of each CONVERGE and COMMIT message, two signatures need to be verified: (1) the signature of the message contents, produced by the sender of the message (first check above) and (2) the aggregate signature in _m.evidence_ (_ValidEvidence(m)_ above). The former can be verified using the sender’s public key (stored in the power table). The latter, being an aggregated signature, requires aggregating public keys of all the participants whose signatures it combines. Notice that the evidence of each message can be signed by a different set of participants, which requires aggregating a linear number of public BLS keys (in system size) per evidence verification. + +However, a participant only needs to verify the evidence once for each *unique* message (in terms of (step, round, value)) received. Moreover, verification can further be reduced to those messages a participant uses to make progress (such as advancing to the next step or deciding), ignoring the rest as they are not needed for progress. This reduces the number of evidence verifications in each step to at most one. + +#### Randomness + +An instance of GossiPBFT requires a seed σ that must be common among all participants due to the dependency on a VRF in the _CONVERGE_ step. As only one random seed is required per GossiPBFT instance, and there is only one GossiPBFT instance per epoch (see below), the random seed for GossiPBFT can be sourced from drand’s output for that epoch in EC. + + +### Synchronization of Participants in the Current Instance + +GossiPBFT ensures termination provided that (i) all participants start the instance at most _Δ_ apart, and (ii) the estimate on Δ is large enough for _Δ_-synchrony in some round (either because of the real network delay recovering from asynchrony or because of the estimate increasing). + +[Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within _Δ=3s_, with a huge majority receiving them even after _Δ=2s_. However, if several participants start the instance _Δ + ε_ after some other participants, termination is not guaranteed for the selected timeouts of _2*Δ_. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. + +The synchronization of participants is performed in the call to updateTimeout(timeout, round) (line 46), and works as follows: + +* Participants start an instance with Δ=2s. +* If the first and second rounds fail to reach termination, participants start the 3rd round with Δ=3s. +* If 5 rounds fail to reach termination (rounds from 0 to 4), participants wait to receive the next drand epoch value to start round 5. This ensures that a potential ε delay between when participants started the instance is not carried over beyond round 4. +* If round 5 fails to reach a decision, participants set exponential timeout increase Δ= 1.3*Δ for every failed round. This ensures termination even if the real network delay increases arbitrarily. + +Additionally, as an optimization, participants could continue to the subsequent step once the execution of the current step has been determined, without waiting for the timeout. For example, if a participant receives _QUALITY_ messages from all participants, it can proceed to the next step without waiting for the timeout. More generally, if the remaining valid messages to be received cannot change the execution of the step, regardless of the values contained in the messages, then a participant should continue to the next step. + + +### Synchronization of Participants across Instances + +The _finalizedTipsets_ data structure is disseminated among the participants and other observers of the Filecoin network in the same manner as the chain itself. In particular, newly joined and temporarily disconnected participants and observers wishing to download and verify the chain can obtain the _finalizedTipsets_ data from other participants or observers (see [main design document](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.gxmabiz2hh3k) for details). + +To verify a finality decision, assuming prior knowledge of an already-final base, a client needs: + +* The power table entries from the base +* A set of signed _DECIDE_ messages for that base that agree on the same value, from distinct senders comprising more than ⅔ QAP in the base +* The public keys for those signers + +A finality certificate brings them together. + +``` +type FinalityCertificate struct { + // Instance, Value as for GossiPBFTMessage (DECIDE) + Instance int + Value []ECTipset + // Indexes in the base power table of the certifiers (bitset) + Signers []bytes + // Aggregated signature of the certifiers + Signature []bytes + // Changes to the base power table implied by the certified tipset + PowerTableDelta []PowerTableDelta +} + +type PowerTableDelta struct { + // Participant with changed power + ParticipantID ActorID + // Change in power from base (signed) + PowerDelta BigInt + // New signing key if relevant (else empty) + SigningKey Key +} +``` + +A finality certificate is analogous to a full block in the EC block exchange protocol. + + +#### Exchange protocol + +Like with EC block exchange, participants follow **a simple request/response protocol to provide a contiguous sequence of finality certificates**. Note that the sequence of certificates is traversed backward, matching block exchange. A finality certificate contains the tipset and the PoF of the tipset (_Signature_). PoFs may vary across participants, but all PoFs must be for the same tipset at the same instance number _i_. + +``` +type Request struct { + // Highest GossiPBFT instance number, to fetch first. + LastInstance int + // Number of certificates to fetch backward from LastInstance, inclusive. + Length int +} + +type Response struct { + // OK, or some error code + Status int + // Sequence of certificates, in reverse order, beginning last requested. + Certificates []FinalityCertificate +} +``` + + +#### Certificate verification + +The client’s algorithm to verify a finality certificate is roughly: + +* Check that the instance number and base tipset follow from the previous certificate +* Load the power and public key for each sender from the base power table +* Verify that the sum of the power of signers exceeds ⅔ of the total power in the table +* Compute the _GossiPBFTMessage_ corresponding to a _DECIDE_ by each sender +* Verify the BLS aggregate signature against the list of messages and keys + +Further, a client prepares to verify the next finality certificate by: + +* Recoding the decided tipset as the new base +* Applying power table deltas to the base power table + +Certificate verification must bottom out in some genesis certificate, which is assumed to be trusted and does not need to be verified. The introduction of the F3 protocol will require such genesis to bootstrap the protocol, and this genesis state is also needed to root a certificate chain. + + +#### Power table deltas + +**A verifier needs each signer's power and public key** (GossiPBFT also needs these for its execution). These are provided by the power table associated with each finalized tipset. + +Assuming some genesis tipset with a known power table, a _GossiPBFTMessage_ can provide a commitment to (CID of) the resulting power table but doesn’t provide the actual entries. A finality certificate includes these as a delta from the previous power table. A verifier can compute the power table for the subsequent certificate by applying these deltas to its base power table. + +Note the power table deltas don’t need to be signed. All _DECIDE_ messages include a commitment to the CID of the resulting power table. Hence, a verifier only needs to confirm that the power table CID as a result of their computation matches that committed to by the signed messages. A finality certificate with incorrect power table deltas cannot be used as a base to verify subsequent instances. + + +#### Verification by Filecoin node (“fast catch-up”) + +A new Filecoin validating node can listen to GossiPBFT gossip to learn about the current instance number. They can then issue exchange requests to other nodes to fetch (in parallel) the complete sequence of finality certificates back to their genesis. **These certificates can be verified without reference to the EC chain.** + +At the same time, the node can sync the headers (and only the headers) of the EC chain and fetch a snapshot of the state at or before the last finalized epoch. They can then verify that: + +* The EC block headers are correctly computed from their ancestors (except for the state root). +* The snapshot state root CID matches that in the block headers. +* The block headers are final. + +This produces a fully trusted chain sync without revalidating the EC chain (which takes days) or fetching the message history. Today, many nodes simply trust that the snapshot they obtain is on the “right” chain; **this fast catch-up is, therefore, both faster and more secure (no eclipse) than revalidating the EC chain.** + + +#### Verification by light client + +A light client can also verify the most recent finalized tipset without validating the EC chain execution. They can fetch just one epoch of block headers and a subset of the state tree to verify some specific state or produce a valid transaction against that state. + + +#### Verification by smart contract + +The finality certificates can be submitted (in order) to a smart contract. The smart contract must maintain the power table of the last finalized tipset in its state. + +A smart contract will never accept a finality certificate earlier than those it has already validated. It will be safe from long-range attacks as long as it is kept reasonably up-to-date with finality decisions as F3 progresses. Like a new client, a new smart contract must be carefully initialized to ensure it follows the right certificate chain. + +Only one such smart contract is needed on a single blockchain execution environment, which can provide the resulting final tipset information to others. + + +## Design Rationale + +Many possibilities were considered for faster finality. We justify the architecture of F3 as the best candidate to achieve fast finality in Filecoin by comparing it with other options: + +* _Improvements to Filecoin's EC_: Longest chain protocols rely on the increasing probability over time that some state is consistent across all participants. In all existing implementations of longest-chain protocols, finalization thus incurs at least tens of minutes. +* _Best-effort finality gadgets_: Ethereum's approach to faster finality involves the introduction of a novel finality gadget. However, this finality gadget requires at least two epochs for finalization, translating to at least more than 30 seconds in Filecoin. In contrast, GossiPBFT can achieve sub-epoch finalization and is only limited by the network speed. Moreover, Ethereum's protocol is yet to be proven correct. In fact, multiple attacks have been described in the literature that show how an adversary can keep the system from ever finalizing blocks, even after fixes. +* _Sub-sample voting_: Avalanche’s sub-sample voting copes with arbitrarily large groups of participants by repeatedly sub-sampling constant-size subsets. Unfortunately, Avalanche's strong network assumptions make the protocol vulnerable to an adversary exploiting network delays. Moreover, Avalanche ensures correctness against an adversary controlling at most ⅕ of participants, versus ⅓ targeted by GossiPBFT. Even when GossiPBFT becomes amenable to committees, for reasonable committees of 600 participants, GossiPBFT already tolerates Avalanche’s ⅕ of total participants with significantly weaker network assumptions. +* _Replacing EC with BFT_: Replacing EC with a BFT protocol (like GossiPBFT) would imply a huge code refactoring, leading to more bugs and significantly more time to develop and productionize the Filecoin upgrade. Furthermore, the combination of EC and F3 is more redundant, ensuring that the system continues operating in the unlikely case that F3 halts. + + +## Backwards Compatibility + +The implementation of F3 involves three main tasks: + +1. Implementing GossiPBFT in a modular way (no changes to existing codebase). +2. Re-formulating the fork-choice rule to the heaviest suffix of the heaviest finalized chain. +3. Implementating the F3 component, which reads the EC chain and marks blocks as final locally. + +Because of changes to the EC fork choice rule, this FIP requires a network upgrade to take effect. + + +## Test Cases + +1. Unit tests +2. Test propagation times during network load to set an estimate on _Δ_ + 1. 3.5k participants sending messages of size >120B over GossipSub (and measure time to receive first, a strong quorum, and all messages). + 2. Same test but for _DECIDE_ messages (which include the passive nodes, not just participants, in the corresponding GossipSub topic). +3. Protocol-specific tests: + - Correctness tests (synchrony is assumed for tests unless stated otherwise): + * Best case: all participants start with the same input. + - Expected Behavior (EB): all participants decide in round 1. + * No synchrony: all participants start with the same input but there is no synchrony at first (less than ⅔ QAP receive the _QUALITY_ messages on time from the rest). Synchrony is restored only after _QUALITY_ finishes. + - EB: all participants decide _baseChain_. + * No quality: participants holding <⅔ QAP start GossiPBFT with a chain _c_ and the rest with a chain _c'_, such that _c_ and _c'_ only share _baseChain_ as prefix. + - EB: all participants decide _baseChain_. + * Prefix quality: participants holding <⅔ QAP start GossiPBFT with a chain _c_ and the rest with a chain _c'_, such that _c_ and _c'_ share some prefix _c''_ that extends _baseChain_. + - EB: all participants decide _c''_. + * Decision of different participants in different rounds: three different partitions, _P_, _Q_, _T_ start with different input chains _c_, _c'_, _c''_, such that _c_ is a prefix of _c'_, and _c'_ of _c''_, respectively, (they strictly extend each other, none being baseChain). QAP of Q >½, while that of _P_ and _T_ are equally split. There is no synchrony between _P_ and _T_ until the beginning of the second round. + - EB: The first round results in participants in _P_ voting for _c_, the rest voting for _c'_ and deciding _c'_. At the start of the second round, once synchrony is restored, _P_ also decides _c'_. + * Membership-change: + - New participants (>⅓ QAP) join the power table and catch up to the latest instance. + - EB: Successful catch-up to the currently executed instance and decision in this instance. + - New participants (much less than ⅓ QAP) join the power table and catch up to the latest instance + - EB: Successful catch-up to currently executed instance and decision in it. Make sure new participants catch up timely with the rest (as progress will happen while they catch up). + * Significant network delays: + - Participants holding ½ QAP start the instance 10 seconds after the other half. + - EB: After round 5, participants are synchronized by drand and decide in this round. + - All messages are delayed by 10 seconds. + - EB: After some round >5, participants can decide. + * Tests on message validity: + - Invalid messages should be discarded; this includes: + * Old/decided instance + * Invalid ticket + * Invalid signature + - Also: signature by a non-participant according to the corresponding power table. + * Invalid evidence + - Evidence containing invalid signature + - Evidence for a different message + - Evidence insufficient by QAP according to the corresponding power table. + * Invalid value + - Value not extending the corresponding baseChain + - Value not being acceptable (after _QUALITY_ step) + - Tests under faults: + * Crashing: + - <⅓ QAP does not send any message from the beginning; the rest share the same input. + - EB: the common input is decided in the first round. + - \>⅔ QAP send _QUALITY_ messages for some chain _c_, while the rest for some chain _c'_ (_c_ and _c'_ only share _baseChain_ as common prefix). After sending _QUALITY_ messages, participants that sent _c_ and that hold <⅓ QAP crash. + - EB: c is decided (participants that sent _c'_ swayed to _c_) in the first round. + - Same setup as the test with [three different partitions](#three-partitions), but participants holding less than ⅓ QAP in Q crash after sending _QUALITY_. One more participant (still in total <⅓ QAP), holding the lowest ticket, crashes in the second round right after sending its _CONVERGE_. + - EB: the chain voted by the crashed participant (i.e., _c'_) is decided. + * Crash-recovery: + - Repeat tests and their EB when, at a given moment, all participants crash and recover (can be done on smaller scales) + - Make tests for crashes at different points of the protocol through fuzzing + * Equivocating: + - Three partitions, _F_ holding <⅓ QAP, _P_ and _Q_ holding the rest of QAP (with _P_ holding more QAP than _Q_). Participants in P do not receive messages from Q timely, and vice versa, in the first round. Participants in _F_ send _QUALITY_ for _c_ to _P_ and _QUALITY_ for _c'_ to _P'_. They do the same with _PREPARE_, _PROPOSE_, _COMMIT_. Synchrony is restored in round 2. + - EB: in the first round, participants in _P_ decide _c_. Participants in _Q_ go to round 2, where they also decide _c_. Participants in _F_ are detected as equivocating by _P_ and _Q_ eventually. + - Same setup as the test with [three different partitions](#three-partitions), but participants holding just less than ⅓ QAP in _Q_ equivocate after sending _QUALITY_ by sending _PREPARE_ and _PROPOSE_ for _c_ to _P_ and for _c'_ to honest participants in _Q_ and _T_. + - EB: honest participants in _Q_ and _T_ decide _c'_ in the first round. Once synchrony is restored in the second round, participants in _P_ decide _c'_ too (perhaps subject to the lower ticket being held by non-Byzantine). + - Flooding messages for future instances/rounds + - Participants holding <⅓ QAP keep sending _QUALITY_ and _PREPARE_ messages for future rounds/instances (as they do not require evidence), intending to flood memory. + - EB: the system can handle buffering a large load of future messages. + - Participants proposing chains that do not extend base chain (EB for all these is that these messages are discarded as the value is invalid): + - Superset (chain proposed includes the _baseChain_ head tipset but not exactly the head tipset) + - Subset (chain proposed contains a tipset included by the _baseChain_ head tipset but not exactly the head tipset) + - Disjoint tipset + - Non-liveness of GossiPBFT for 900 epochs or more. The setup for this is >⅓ QAP crash. + - Expected behavior: + - EC finalizes tipsets + - Honest participants do not participate anymore to finalize anything (handbrake) +4. Integration tests: + - Test 0th instance: all participants start by assuming _baseChain_ is epoch number (_upgradeEpoch_ minus 900). + - EB: F3 successfully bootstraps with a decision. + - Test under Byzantine behavior (<⅓ QAP) and network delays. + - Test upgrade: same as above, but perform a test in calibration (or simulated upgrade), not in isolation (as above). + - F3 decides a chain in an instance that is not extended by the current EC chain + - EB: All participants change their heaviest chain to extend the new finalized head tipset. +5. Performance tests (realistic but different geographical and weight distributions and number of participants): + - Latency + - Throughput + - Practical limit on participation + + +## Security Considerations + +The modifications proposed in this FIP have far-reaching implications for the security of the system. This FIP changes Filecoin at a fundamental level: from considering tipsets as final after some time to finalizing them after a quorum of participants reach an agreement. We list here the security considerations this modification entails. + +* **Censorship.** F3 and GossiPBFT are designed with censorship resistance in mind. The updated fork choice rule means that an adversary controlling at least more than ⅓ QAP can try to perform a censorship attack if honest participants start an instance of GossiPBFT proposing at least two distinct inputs. While this attack is theoretically possible, it is notably hard to perform on F3 given the _QUALITY_ step of GossiPBFT and other mitigation strategies specifically put in place to protect against this (See [GossipBFT's design document, Appendix B](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.3563x64us9fj) for more details on the attack and mitigations). We strongly believe that, even against a majority adversary, the mitigations designed will prevent such an attack. +* **Liveness.** Implementing F3 introduces the risk that an adversary controlling at least ⅓ QAP prevents termination of a GossiPBFT instance. In that case, the F3 component would halt, not finalizing any tipset anymore. At the same time, EC would still operate, outputting tipsets and considering them final after 900 epochs (see [Fast Finality in Filecoin (F3), Appendix A](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit#heading=h.iwwgfqxud6bn) for more details). The liveness of the system is thus not affected by attacks on the liveness of F3. +* **Safety.** Implementing F3 ensures the safety of finalized outputs during regular or even congested networks against a Byzantine adversary controlling less than ⅓ QAP. For stronger adversaries, F3 provides mitigations to prevent censorship attacks, as outlined above. If deemed necessary, the punishment and recovery from coalitions in the event of an attempted attack on safety can be explored in future FIPs. Note that safety is already significantly improved by F3 compared to the status quo: F3 provides safety of finalized outputs two orders of magnitude faster than the current estimate of 900 epochs during regular network operation. +* **Denial-of-service (DoS).** The implementation of the F3 preserves resistance against DoS attacks currently ensured by Filecoin, thanks to the fully leaderless nature of GossiPBFT and to the use of a VRF to self-assign tickets during the CONVERGE step. +* **Committees.** This FIP proposes to have all participants run all instances of GossiPBFT. While this ensures optimal resilience against a Byzantine adversary, it can render the system unusable if the number of participants grows too large. While we are still evaluating the maximum practical number of participants in F3, it is expected to be at least one order of magnitude greater than the current number of participants in Filecoin. This introduces an attack vector: if the scalability limit is 100,000 participants, a participant holding as little as 3% of the current QAP can perform a Sybil attack to render the system unusable, with the minimum QAP required per identity. As a result, the implementation should favor the messages of the more powerful participants if the number of participants grows too large. Given that favoring more powerful participants discriminates against the rest, affecting decentralization, amending F3 to use committees in the event of the number of participants exceeding the practical limit will be the topic of a future FIP, as well as the analysis of optimized message aggregation in the presence of self-selected committees. + + +## Incentive Considerations + +Participating in GossiPBFT only entails verifying O(n) and generating O(1) signatures per participant. If not enough participants follow the protocol, the liveness of F3 will be affected. This means that the service offered is affected, but also that participants do not receive rewards from block proposals for the period in which they do not participate. Consequently, we do not believe additional incentives for participation are necessary, as the modifications in this FIP significantly improve the system and the additional computational and communication costs do not substantially alter the cost structure of running a Filecoin node. + +Furthermore, incentivizing all messages and verification thereof is impossible: this would require consensus on which messages have been sent (which would entail even more messages, these new ones unverified). Nevertheless, subsequent FIPs can provide more incentives, such as rewarding participants whose signatures are listed in agreed-upon PoFs or slash/denylist participants who sign equivocating messages. + + +## Product Considerations + +1. Applications built on FVM and IPC do not need to wait for 900 epochs and can instead benefit from fast finalization times within the order of tens of seconds. +2. Other applications built on Filecoin (e.g., Glif, Axelar, Wormhole, exchanges) can also provide fast finality and low latency without compromising security. +3. Safe, verifiable, fast bridging to other networks becomes possible. + + +## Implementation + +We refer to the stand-alone implementation in a simulated environment in the [go-f3](https://github.com/filecoin-project/go-f3) repository. Work is ongoing on a reference lotus implementation (to be provided soon). + +## Copyright + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From e3d1d7ac6a331d43f50d6d4558f21325eaa45ef2 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 18:18:32 +0100 Subject: [PATCH 02/33] Clean up spacing --- FIPS/fip-xxxx.md | 434 ++++++++++++++++++++++++----------------------- 1 file changed, 221 insertions(+), 213 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index bd9ddb03..b23bf99b 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -34,7 +34,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t ## Specification -### Background +### Background [Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. @@ -42,7 +42,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t Two or more tipsets of the same epoch with different parent tipsets (like tipsets _C_ and _C'_ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant _p1_ is not (yet) aware of tipset _D_, it would consider _C_ the heaviest tipset with the canonical chain _[G A B C]_. Another participant _p2_ aware of tipset _D_ will consider _[G A C’ D]_ to be the canonical chain. Once _p1_ becomes aware of tipset _D_, it will update its canonical chain to _[G A C’ D]_ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. -In EC and, generally, longest-chain protocols, the probability of a path from some tipset _h_ to the genesis tipset becoming finalized increases with the number of descendant tipsets of _h_. This happens because the weight of the heaviest chain increases the fastest, as the tipsets with the most new blocks are appended to it (assuming that honest participants form a majority). In the particular case of EC, in each epoch, most created blocks are expected to come from honest participants and thus extend the heaviest chain. Consequently, it becomes progressively harder for a different path to overcome that weight. Over time, the probability of a tipset never undergoing a reorganization becomes high enough that the tipset is considered final for all practical purposes. In the Filecoin network, a tipset that is part of the heaviest chain is considered final after 900 epochs (or, equivalently, 7.5 hours) from its proposal. +In EC and, generally, longest-chain protocols, the probability of a path from some tipset _h_ to the genesis tipset becoming finalized increases with the number of descendant tipsets of _h_. This happens because the weight of the heaviest chain increases the fastest, as the tipsets with the most new blocks are appended to it (assuming that honest participants form a majority). In the particular case of EC, in each epoch, most created blocks are expected to come from honest participants and thus extend the heaviest chain. Consequently, it becomes progressively harder for a different path to overcome that weight. Over time, the probability of a tipset never undergoing a reorganization becomes high enough that the tipset is considered final for all practical purposes. In the Filecoin network, a tipset that is part of the heaviest chain is considered final after 900 epochs (or, equivalently, 7.5 hours) from its proposal. ### F3 Overview and Interaction with EC @@ -68,7 +68,7 @@ We further adapt our protocols to align the actions of honest and rational parti F3 and its implementation GossiPBFT provide additional robustness for strong adversaries that control more than ⅓ QAP, such as: -* Censorship resistance against a coalition of rational participants trying to leak power, without providing firm guarantees. +* Censorship resistance against a coalition of rational participants trying to leak power, without providing firm guarantees. * Resilience to long-range attacks by an adversary controlling up to less than ⅔ QAP of any old power table. @@ -77,7 +77,7 @@ F3 and its implementation GossiPBFT provide additional robustness for strong adv F3 uses GossipSub (like Filecoin EC) to disseminate protocol messages, implementing a broadcast channel among participants. We assume and model GossipSub to satisfy the following properties of the _best-effort broadcast primitive_ (denoted _BEBroadcast_ hereafter): * If _p_ and _p’_ are honest, then every message broadcast by _p_ is eventually delivered by _p’_. -* No message with sender _p_ is delivered unless it was previously broadcast by _p_. +* No message with sender _p_ is delivered unless it was previously broadcast by _p_. ### Partially Synchronous Model and Δ-Synchrony @@ -89,34 +89,34 @@ In practice, if GossipSub is used for _BEBroadcast_, _Δ_ is effectively the ass For termination, we assume a classical partially synchronous model with an unknown bound on communication delays among non-Byzantine participants. -### Properties of F3 +### Properties of F3 F3 is not identical to classical consensus, however similar to it. In a nutshell, the reasons why EC and Filecoin should not rely on classical consensus properties (implemented by existing off-the-shelf BFT consensus protocol) for fast finality are twofold: EC incentive compatibility and resilience to Filecoin power leakage attacks in case of a strong adversary. We refer to the accompanying document [Appendix A: F3 requirements specific to Filecoin and EC](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.jg4hdeovc1zg) for more details. -With this in mind, the F3 component interface and properties are given below. +With this in mind, the F3 component interface and properties are given below. > **Interface and properties of F3 at participant p:** -> -> `F3.invoke (int i, chain canonical, chain baseChain)` **returns** (we say finalizes) `(int i, chain h, proof_of_finality PoF)` -> +> +> `F3.invoke (int i, chain canonical, chain baseChain)` **returns** (we say finalizes) `(int i, chain h, proof_of_finality PoF)` +> > **Properties:** -> +> > **Agreement.** If two honest participants finalize _(i,h,*)_ and _(i,h’,*)_, then _h_ = _h_’. -> -> **Validity.** If an honest participant finalizes _(i,h,*)_, then _h_ is a prefix of the canonical input chain of some honest participant _p’_ in instance _i_. -> -> **Proof of Finality.** If an honest participant finalizes _(i,h,PoF)_, then _PoF_ is signed by ⅔ QAP majority corresponding to the _PowerTable(baseChain)’_ input in instance _i_ of some honest participant _p’_. -> -> **Progress.** If the system is _Δ_-synchronous, i.e., +> +> **Validity.** If an honest participant finalizes _(i,h,*)_, then _h_ is a prefix of the canonical input chain of some honest participant _p’_ in instance _i_. +> +> **Proof of Finality.** If an honest participant finalizes _(i,h,PoF)_, then _PoF_ is signed by ⅔ QAP majority corresponding to the _PowerTable(baseChain)’_ input in instance _i_ of some honest participant _p’_. +> +> **Progress.** If the system is _Δ_-synchronous, i.e., > * All honest participants can communicate within a known time bound _Δ_, and -> * no honest participants invokes _F3(i, *, *)_ later than _Δ_ after another participant invokes _F3(i, *, *)_, -> +> * no honest participants invokes _F3(i, *, *)_ later than _Δ_ after another participant invokes _F3(i, *, *)_, +> > Let c be the heaviest common prefix of the inputs of all honest participants in instance _i_. Then, if an honest participant finalizes _(i,c’,*)_, _c is a prefix of c_’ with probability > 0.5. -> +> > **Termination.** If the system is _Δ_-synchronous, every call to F3 eventually returns with probability _1_. -> -> **EC Incentive compatibility.** An honest participant never contributes to gathering ⅔ QAP (super-majority) of votes for a chain _c_ which its local EC instance did not already deliver unless it already observes evidence of such a super-majority for chain _c_. -> +> +> **EC Incentive compatibility.** An honest participant never contributes to gathering ⅔ QAP (super-majority) of votes for a chain _c_ which its local EC instance did not already deliver unless it already observes evidence of such a super-majority for chain _c_. +> > `F3.ECupdate (int i, chain c)`: Participant _p_ updates F3 instance _i_ with chain _c_, which its EC instance locally delivered (relevant to EC incentive compatibility) We later show the specific estimate chosen for _Δ_ to optimize termination (See [here](#Synchronization-of-Participants-in-the-Current-Instance)). @@ -138,7 +138,7 @@ A participant that invokes the _GossiPBFT()_ function starts a consensus instanc Verify(PoF, decision, participants) → boolean ``` -This function uses the _PoF_ to verify that _decision_ was the output of some instance of consensus executed among the _participants_. +This function uses the _PoF_ to verify that _decision_ was the output of some instance of consensus executed among the _participants_. ### Power Table and Consensus Participants @@ -165,12 +165,12 @@ while True: participants ← PowerTable(finalizedTipsets[i-1].tipset) proposal ← ChainHead() finalizedTipset, PoF ← GossiPBFT(i, proposal, participants) - finalizedTipsets[i].tipset ← finalizedTipset - finalizedTipsets[i].PoF ← PoF - i ← i + 1 + finalizedTipsets[i].tipset ← finalizedTipset + finalizedTipsets[i].PoF ← PoF + i ← i + 1 ``` -Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named _finalizedTipsets_. It contains one _finalizedTipsets[i]_ entry per consensus instance where _finalizedTipsets[i].tipset_ and _finalizedTipsets[i].PoF_ denote, respectively, the tipset and PoF output by consensus instance _i_. A participant considers a tipset finalized if it is included in _finalizedTipsets_ or is an ancestor of some tipset included in _finalizedTipsets_. +Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named _finalizedTipsets_. It contains one _finalizedTipsets[i]_ entry per consensus instance where _finalizedTipsets[i].tipset_ and _finalizedTipsets[i].PoF_ denote, respectively, the tipset and PoF output by consensus instance _i_. A participant considers a tipset finalized if it is included in _finalizedTipsets_ or is an ancestor of some tipset included in _finalizedTipsets_. The algorithm starts by initializing _finalizedTipsets[0]_ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration _i_ of the loop, it takes the following steps (see [this document](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit) for details): @@ -186,27 +186,27 @@ To prevent useless instances of GossiPBFT deciding on the same _baseChain_ becau EC needs to be modified to accommodate the finalization of tipsets by F3. **This is the only change to EC this FIP introduces.** -The current EC fork-choice rule selects, from all the known tipsets, the tipset backed by the most weight. As the F3 component finalizes tipsets, the fork-choice rule must ensure that the heaviest finalized chain is always a prefix of the heaviest chain, preventing reorganizations of the already finalized chain. +The current EC fork-choice rule selects, from all the known tipsets, the tipset backed by the most weight. As the F3 component finalizes tipsets, the fork-choice rule must ensure that the heaviest finalized chain is always a prefix of the heaviest chain, preventing reorganizations of the already finalized chain. -We achieve this by adjusting the definition of weight for a finalized prefix: the heaviest finalized chain is the one that **matches exactly the tipsets finalized by F3**, in that a tipset _T’_ that is a superset of finalized tipset _T_ in the same epoch is not heavier than _T_ itself, despite it being backed by more EC power. +We achieve this by adjusting the definition of weight for a finalized prefix: the heaviest finalized chain is the one that **matches exactly the tipsets finalized by F3**, in that a tipset _T’_ that is a superset of finalized tipset _T_ in the same epoch is not heavier than _T_ itself, despite it being backed by more EC power. This redefinition of the heaviest chain is consistent with the abstract notion of the heaviest chain being backed by the most power because a finalized tipset has been backed by a super-majority of participants in GossiPBFT. In contrast, any non-finalized block in the same epoch is only backed in that epoch by the EC proposer. -We illustrate the updated rule in the following figure, where blocks in blue are finalized blocks, and all blocks are assumed to be proposed by a proposer holding only one EC ticket (the weight of a chain is the number of blocks): +We illustrate the updated rule in the following figure, where blocks in blue are finalized blocks, and all blocks are assumed to be proposed by a proposer holding only one EC ticket (the weight of a chain is the number of blocks): ![](https://hackmd.io/_uploads/SJumBiT8p.png) -The current EC fork-choice rule would select the tipset _{D0, D1}_ as the head of the heaviest chain. However, the heaviest finalized tipset is _{C3}_, which is not an ancestor of _{D0, D1}_. Therefore, the new fork choice rule selects _{D3}_ as the head of the heaviest chain. The reason why _D4_ is not selected is that its parent tipset does not exactly match the finalized tipset _{C3}_, but a superset of it, i.e. _{C3, C4}_. +The current EC fork-choice rule would select the tipset _{D0, D1}_ as the head of the heaviest chain. However, the heaviest finalized tipset is _{C3}_, which is not an ancestor of _{D0, D1}_. Therefore, the new fork choice rule selects _{D3}_ as the head of the heaviest chain. The reason why _D4_ is not selected is that its parent tipset does not exactly match the finalized tipset _{C3}_, but a superset of it, i.e. _{C3, C4}_. -### Bootstrapping +### Bootstrapping -Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, _upgradeEpoch_, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the _upgradeEpoch_ minus the 900-epoch lookback as the head tipset of the first _baseChain_, which is assumed by design to be common to all participants. +Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, _upgradeEpoch_, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the _upgradeEpoch_ minus the 900-epoch lookback as the head tipset of the first _baseChain_, which is assumed by design to be common to all participants. ### GossiPBFT Consensus -This section provides the specification of GossiPBFT, the consensus protocol that is iteratively instantiated by the F3 loop and returns a decision (in the form of an F3-finalized chain) and a PoF per instance. +This section provides the specification of GossiPBFT, the consensus protocol that is iteratively instantiated by the F3 loop and returns a decision (in the form of an F3-finalized chain) and a PoF per instance. GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the **final** decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent (see [main design document](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit) for details). @@ -217,8 +217,8 @@ GossiPBFT was designed with the Filecoin network in mind and presents a set of f * Unlike PBFT, HotStuff, Tendermint, and many other protocols in this space, GossiPBFT is a leaderless protocol. This property makes it resistant to denial of service attacks because no designated participant represents the weakest link. * Low latency. During periods of synchrony and honest proposers, GossiPBFT will finish in three communication steps. We expect this to happen within tens of seconds. * GossiPBFT has been tailored with Filecoin and open blockchains in mind, with strong resilience against censorship attacks and incentive compatibility for rational participants. -* GossiPBFT is tailored to using a broadcast communication primitive, GossipSub, which Filecoin already uses. -* GossipPBFT internal invariants, on which the protocol correctness is based, are very similar to those of the seminal PBFT protocol, making protocol correctness easier to establish. +* GossiPBFT is tailored to using a broadcast communication primitive, GossipSub, which Filecoin already uses. +* GossipPBFT internal invariants, on which the protocol correctness is based, are very similar to those of the seminal PBFT protocol, making protocol correctness easier to establish. #### Message format, signatures, and equivocation @@ -227,60 +227,60 @@ Messages include the following fields: _0 and their public keys. // This is expected to be calculated from the EC chain state and provided to GossiPBFT. // In descending order to provide unique representation. type PowerTable { - Entries []PowerTableEntry + Entries []PowerTableEntry } type PowerTableEntry { - ParticipantID ActorID - Power BigInt - Key BLSPublicKey + ParticipantID ActorID + Power BigInt + Key BLSPublicKey } // Aggregated list of GossiPBFT messages with the same instance, round and value. Used as evidence for justification of messages type AggregatedEvidence { - // Enumeration of QUALITY, PREPARE, COMMIT, CONVERGE, DECIDE - MsgType int - // Chain of tipsets proposed/voted for finalisation in this instance. - // Non-empty: the first entry is the base tipset finalised in instance-1 - Value []ECTipset - // GossiPBFT instance number - Instance int - // GossiPBFT round - Round int - // Indexes in the base power table of the signers (bitset) - Signers []bytes - // BLS aggregate signature of signers - Signature []bytes + // Enumeration of QUALITY, PREPARE, COMMIT, CONVERGE, DECIDE + MsgType int + // Chain of tipsets proposed/voted for finalisation in this instance. + // Non-empty: the first entry is the base tipset finalised in instance-1 + Value []ECTipset + // GossiPBFT instance number + Instance int + // GossiPBFT round + Round int + // Indexes in the base power table of the signers (bitset) + Signers []bytes + // BLS aggregate signature of signers + Signature []bytes } ``` @@ -303,18 +303,24 @@ A set of messages _M_ that does not contain equivocating messages is called _cle * `StrongQuorum(prefix,M)` * Where _M_ is a clean set of messages of the same type and the same round. * Let _P_ be the set of participants who are senders of messages in _M_ such that their message contains a value with _prefix_ as a prefix. More precisely: - `Let P={p : ∃ m∈ M: m.sender=p AND isPrefix(prefix,m.value)}` - then the predicate returns _True_ iff _Power( P )>2/3_ + ``` + Let P={p : ∃ m∈ M: m.sender=p AND isPrefix(prefix,m.value)} + ``` + then the predicate returns _True_ iff _Power( P )>2/3_ * `HasStrongQuorumValue(M)` * Where _M_ is a clean set of messages of the same type and the same round * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>2/3_. More precisely: - `HasStrongQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>2/3` + ``` + HasStrongQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>2/3 + ``` * `StrongQuorumValue(M)` * Returns _v_ if _HasStrongQuorumValue(M)_ holds, nil otherwise. * `HasWeakQuorumValue(M)` * Where _M_ is a clean set of messages of the same type and the same round * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>1/3_. More precisely: - `HasWeakQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>1/3` + ``` + HasWeakQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>1/3 + ``` * `WeakQuorumValue(M)` * Returns _v_ if _HasWeakQuorumValue(M)_ holds, nil otherwise. * `LowestTicketProposal(M)` @@ -323,7 +329,9 @@ A set of messages _M_ that does not contain equivocating messages is called _cle * If _M ≠ ∅_, the predicate returns _m.value_, such that _m_ is the message in _M_ with the lowest ticket (_m.ticket_). * `Aggregate(M)` * Where _M_ is a clean set of messages of the same type _T_, round _r_, and instance _i_, with _v=StrongQuorumValue(M)≠nil_. - `Let M' ← {m ∈ M : m.value = StrongQuorumValue(M)}` + ``` + Let M' ← {m ∈ M : m.value = StrongQuorumValue(M)} + ``` * Returns a tuple __ where _participants_ are all participants such that _m.sender ∈ M'_ (in some compact/compressed representation, i.e. a bitmask with optional run-length encoding) and _agg-sig_ is an aggregate signature (BLS) across all of those participants on _m.i||m.T||m.r||m.v_ for some _m ∈ M'_. @@ -333,148 +341,148 @@ We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per roun ``` F3(inputChain, baseChain) returns (chain, PoF): -1: round ← 0; -2: decideSent ← False; -3: proposal ← inputChain; \* holds what the participant locally believes should be a decision -4: timeout ← 2*Δ -5: ECCompatibleChains ← all prefixes of proposal, not lighter than baseChain -6: value ← proposal \* used to communicate the voted value to others (proposal or 丄) -7: evidence ← nil \* used to communicate optional evidence for the voted value - -8: while (not decideSent) { -9: if (round = 0) -10: BEBroadcast ; trigger (timeout) -11: collect a clean set M of valid QUALITY messages - until StrongQuorum(proposal, M) OR timeout expires -12: let C={prefix : IsPrefix(prefix,proposal) and StrongQuorum(prefix,M)} -13: if (C = ∅) -14: proposal ← baseChain \* no proposals of high-enough quality -15: else -16: proposal ← heaviest prefix ∈ C \* this becomes baseChain or sth heavier -17: value ← proposal - -18: if (round > 0): \* CONVERGE -19: ticket ← VRF(Randomness(baseChain) || round) -20: value ← proposal \* set local proposal as value in CONVERGE message -21: BEBroadcast ; trigger(timeout) -22: collect a clean set M of valid CONVERGE msgs from this round - until timeout expires -23: value ← LowestTicketProposal(M) \* leader election -24: if value ∈ ECCompatibleChains \* see also lines 54-57 -25: proposal ← value \* we sway proposal if the value is EC compatible -26: else -27: value ← 丄 \* vote for not deciding in this round - -28: BEBroadcast ; trigger(timeout) -29: collect a clean set M of valid msgs \* match PREPARE value against local proposal -until Power(M) > ⅔ OR timeout expires -30: if (Power(M)>⅔) \* strong quorum of PREPAREs for local proposal -31: value ← proposal \* vote for deciding proposal (COMMIT) -32: evidence ← Aggregate(M) \* strong quorum of PREPAREs is evidence -33: else -34: value ← 丄 \* vote for not deciding in this round -35: evidence ← nil - -36: BEBroadcast ; trigger(timeout) -37: collect a clean set M of valid COMMIT messages from this round -until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) - OR (timeout expires AND Power(M)>2/3) -38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide -39: BEBroadcast ; trigger (timeout) +11: collect a clean set M of valid QUALITY messages + until StrongQuorum(proposal, M) OR timeout expires +12: let C={prefix : IsPrefix(prefix,proposal) and StrongQuorum(prefix,M)} +13: if (C = ∅) +14: proposal ← baseChain \* no proposals of high-enough quality +15: else +16: proposal ← heaviest prefix ∈ C \* this becomes baseChain or sth heavier +17: value ← proposal + +18: if (round > 0): \* CONVERGE +19: ticket ← VRF(Randomness(baseChain) || round) +20: value ← proposal \* set local proposal as value in CONVERGE message +21: BEBroadcast ; trigger(timeout) +22: collect a clean set M of valid CONVERGE msgs from this round + until timeout expires +23: value ← LowestTicketProposal(M) \* leader election +24: if value ∈ ECCompatibleChains \* see also lines 54-57 +25: proposal ← value \* we sway proposal if the value is EC compatible +26: else +27: value ← 丄 \* vote for not deciding in this round + +28: BEBroadcast ; trigger(timeout) +29: collect a clean set M of valid msgs \* match PREPARE value against local proposal + until Power(M) > ⅔ OR timeout expires +30: if (Power(M)>⅔) \* strong quorum of PREPAREs for local proposal +31: value ← proposal \* vote for deciding proposal (COMMIT) +32: evidence ← Aggregate(M) \* strong quorum of PREPAREs is evidence +33: else +34: value ← 丄 \* vote for not deciding in this round +35: evidence ← nil + +36: BEBroadcast ; trigger(timeout) +37: collect a clean set M of valid COMMIT messages from this round + until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) + OR (timeout expires AND Power(M)>2/3) +38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide +39: BEBroadcast 0. - return False -If m.step ∈ {CONVERGE, COMMIT} AND | CONVERGE, COMMIT - NOT ValidEvidence(m) | must contain valid evidence. - return False +Valid(m): | For a message m to be valid, + +If m is not properly signed: | m must be properly signed. + return False +If m.step = QUALITY AND | A QUALITY message must + NOT IsPrefix(baseChain, m.proposal) | contain a proposal prefixed + return Fals | with baseChain. +If m.step = CONVERGE AND | A CONVERGE message + (m.ticket does not pass VRF validation | must have a valid VRF ticket + OR m.round = 0) | and round > 0. + return False +If m.step ∈ {CONVERGE, COMMIT} AND | CONVERGE, COMMIT + NOT ValidEvidence(m) | must contain valid evidence. + return False return True ``` The _ValidEvidence()_ predicate is defined below (for other definitions used below, see [Preliminaries](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.ygq5svj4e7ap)). Note that _QUALITY_, _PREPARE_ and _DECIDE_ messages do not need evidence. In fact, _DECIDE_ does not need any protocol-specific validation, since a weak quorum of _DECIDE_ with the same value is required to trigger any execution of the protocol. ``` -ValidEvidence(m): - +ValidEvidence(m): -(m = | valid CONVERGE -AND (∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum - AND ((∀ m' ∈ M: m'.step = COMMIT AND m'.value = 丄) | of COMMIT msgs for 丄 - OR (∀ m' ∈ M: m'.step = PREPARE AND | or PREPARE msgs for - m'.value = m.value)) | CONVERGE value -AND (∀ m' ∈ M: m'.round = m.round-1) | from previous round +(m = | valid CONVERGE +AND (∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum + AND ((∀ m' ∈ M: m'.step = COMMIT AND m'.value = 丄) | of COMMIT msgs for 丄 + OR (∀ m' ∈ M: m'.step = PREPARE AND | or PREPARE msgs for + m'.value = m.value)) | CONVERGE value + AND (∀ m' ∈ M: m'.round = m.round-1) | from previous round -OR (m = | valid COMMIT - AND ((∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum +OR (m = | valid COMMIT + AND ((∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum AND ∀ m' ∈ M: m'.step = PREPAR | of PREPARE messages - AND ∀ m' ∈ M: m'.round = m.round | from the same round - AND ∀ m' ∈ M: m'.value = m.value) | for the same value, or - OR (m.value = 丄)) | COMMIT is for 丄 with - | no evidence + AND ∀ m' ∈ M: m'.round = m.round | from the same round + AND ∀ m' ∈ M: m'.value = m.value) | for the same value, or + OR (m.value = 丄)) | COMMIT is for 丄 with + | no evidence ``` ### Evidence verification complexity Note that during the validation of each CONVERGE and COMMIT message, two signatures need to be verified: (1) the signature of the message contents, produced by the sender of the message (first check above) and (2) the aggregate signature in _m.evidence_ (_ValidEvidence(m)_ above). The former can be verified using the sender’s public key (stored in the power table). The latter, being an aggregated signature, requires aggregating public keys of all the participants whose signatures it combines. Notice that the evidence of each message can be signed by a different set of participants, which requires aggregating a linear number of public BLS keys (in system size) per evidence verification. -However, a participant only needs to verify the evidence once for each *unique* message (in terms of (step, round, value)) received. Moreover, verification can further be reduced to those messages a participant uses to make progress (such as advancing to the next step or deciding), ignoring the rest as they are not needed for progress. This reduces the number of evidence verifications in each step to at most one. +However, a participant only needs to verify the evidence once for each *unique* message (in terms of (step, round, value)) received. Moreover, verification can further be reduced to those messages a participant uses to make progress (such as advancing to the next step or deciding), ignoring the rest as they are not needed for progress. This reduces the number of evidence verifications in each step to at most one. #### Randomness An instance of GossiPBFT requires a seed σ that must be common among all participants due to the dependency on a VRF in the _CONVERGE_ step. As only one random seed is required per GossiPBFT instance, and there is only one GossiPBFT instance per epoch (see below), the random seed for GossiPBFT can be sourced from drand’s output for that epoch in EC. -### Synchronization of Participants in the Current Instance +### Synchronization of Participants in the Current Instance GossiPBFT ensures termination provided that (i) all participants start the instance at most _Δ_ apart, and (ii) the estimate on Δ is large enough for _Δ_-synchrony in some round (either because of the real network delay recovering from asynchrony or because of the estimate increasing). -[Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within _Δ=3s_, with a huge majority receiving them even after _Δ=2s_. However, if several participants start the instance _Δ + ε_ after some other participants, termination is not guaranteed for the selected timeouts of _2*Δ_. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. +[Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within _Δ=3s_, with a huge majority receiving them even after _Δ=2s_. However, if several participants start the instance _Δ + ε_ after some other participants, termination is not guaranteed for the selected timeouts of _2*Δ_. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. The synchronization of participants is performed in the call to updateTimeout(timeout, round) (line 46), and works as follows: * Participants start an instance with Δ=2s. -* If the first and second rounds fail to reach termination, participants start the 3rd round with Δ=3s. +* If the first and second rounds fail to reach termination, participants start the 3rd round with Δ=3s. * If 5 rounds fail to reach termination (rounds from 0 to 4), participants wait to receive the next drand epoch value to start round 5. This ensures that a potential ε delay between when participants started the instance is not carried over beyond round 4. * If round 5 fails to reach a decision, participants set exponential timeout increase Δ= 1.3*Δ for every failed round. This ensures termination even if the real network delay increases arbitrarily. @@ -495,24 +503,24 @@ A finality certificate brings them together. ``` type FinalityCertificate struct { - // Instance, Value as for GossiPBFTMessage (DECIDE) - Instance int - Value []ECTipset - // Indexes in the base power table of the certifiers (bitset) - Signers []bytes - // Aggregated signature of the certifiers - Signature []bytes - // Changes to the base power table implied by the certified tipset - PowerTableDelta []PowerTableDelta + // Instance, Value as for GossiPBFTMessage (DECIDE) + Instance int + Value []ECTipset + // Indexes in the base power table of the certifiers (bitset) + Signers []bytes + // Aggregated signature of the certifiers + Signature []bytes + // Changes to the base power table implied by the certified tipset + PowerTableDelta []PowerTableDelta } type PowerTableDelta struct { - // Participant with changed power - ParticipantID ActorID - // Change in power from base (signed) - PowerDelta BigInt - // New signing key if relevant (else empty) - SigningKey Key + // Participant with changed power + ParticipantID ActorID + // Change in power from base (signed) + PowerDelta BigInt + // New signing key if relevant (else empty) + SigningKey Key } ``` @@ -521,21 +529,21 @@ A finality certificate is analogous to a full block in the EC block exchange pro #### Exchange protocol -Like with EC block exchange, participants follow **a simple request/response protocol to provide a contiguous sequence of finality certificates**. Note that the sequence of certificates is traversed backward, matching block exchange. A finality certificate contains the tipset and the PoF of the tipset (_Signature_). PoFs may vary across participants, but all PoFs must be for the same tipset at the same instance number _i_. +Like with EC block exchange, participants follow **a simple request/response protocol to provide a contiguous sequence of finality certificates**. Note that the sequence of certificates is traversed backward, matching block exchange. A finality certificate contains the tipset and the PoF of the tipset (_Signature_). PoFs may vary across participants, but all PoFs must be for the same tipset at the same instance number _i_. ``` type Request struct { - // Highest GossiPBFT instance number, to fetch first. - LastInstance int - // Number of certificates to fetch backward from LastInstance, inclusive. - Length int + // Highest GossiPBFT instance number, to fetch first. + LastInstance int + // Number of certificates to fetch backward from LastInstance, inclusive. + Length int } type Response struct { - // OK, or some error code - Status int - // Sequence of certificates, in reverse order, beginning last requested. - Certificates []FinalityCertificate + // OK, or some error code + Status int + // Sequence of certificates, in reverse order, beginning last requested. + Certificates []FinalityCertificate } ``` @@ -560,7 +568,7 @@ Certificate verification must bottom out in some genesis certificate, which is a #### Power table deltas -**A verifier needs each signer's power and public key** (GossiPBFT also needs these for its execution). These are provided by the power table associated with each finalized tipset. +**A verifier needs each signer's power and public key** (GossiPBFT also needs these for its execution). These are provided by the power table associated with each finalized tipset. Assuming some genesis tipset with a known power table, a _GossiPBFTMessage_ can provide a commitment to (CID of) the resulting power table but doesn’t provide the actual entries. A finality certificate includes these as a delta from the previous power table. A verifier can compute the power table for the subsequent certificate by applying these deltas to its base power table. @@ -591,15 +599,15 @@ The finality certificates can be submitted (in order) to a smart contract. The s A smart contract will never accept a finality certificate earlier than those it has already validated. It will be safe from long-range attacks as long as it is kept reasonably up-to-date with finality decisions as F3 progresses. Like a new client, a new smart contract must be carefully initialized to ensure it follows the right certificate chain. -Only one such smart contract is needed on a single blockchain execution environment, which can provide the resulting final tipset information to others. +Only one such smart contract is needed on a single blockchain execution environment, which can provide the resulting final tipset information to others. ## Design Rationale Many possibilities were considered for faster finality. We justify the architecture of F3 as the best candidate to achieve fast finality in Filecoin by comparing it with other options: -* _Improvements to Filecoin's EC_: Longest chain protocols rely on the increasing probability over time that some state is consistent across all participants. In all existing implementations of longest-chain protocols, finalization thus incurs at least tens of minutes. -* _Best-effort finality gadgets_: Ethereum's approach to faster finality involves the introduction of a novel finality gadget. However, this finality gadget requires at least two epochs for finalization, translating to at least more than 30 seconds in Filecoin. In contrast, GossiPBFT can achieve sub-epoch finalization and is only limited by the network speed. Moreover, Ethereum's protocol is yet to be proven correct. In fact, multiple attacks have been described in the literature that show how an adversary can keep the system from ever finalizing blocks, even after fixes. +* _Improvements to Filecoin's EC_: Longest chain protocols rely on the increasing probability over time that some state is consistent across all participants. In all existing implementations of longest-chain protocols, finalization thus incurs at least tens of minutes. +* _Best-effort finality gadgets_: Ethereum's approach to faster finality involves the introduction of a novel finality gadget. However, this finality gadget requires at least two epochs for finalization, translating to at least more than 30 seconds in Filecoin. In contrast, GossiPBFT can achieve sub-epoch finalization and is only limited by the network speed. Moreover, Ethereum's protocol is yet to be proven correct. In fact, multiple attacks have been described in the literature that show how an adversary can keep the system from ever finalizing blocks, even after fixes. * _Sub-sample voting_: Avalanche’s sub-sample voting copes with arbitrarily large groups of participants by repeatedly sub-sampling constant-size subsets. Unfortunately, Avalanche's strong network assumptions make the protocol vulnerable to an adversary exploiting network delays. Moreover, Avalanche ensures correctness against an adversary controlling at most ⅕ of participants, versus ⅓ targeted by GossiPBFT. Even when GossiPBFT becomes amenable to committees, for reasonable committees of 600 participants, GossiPBFT already tolerates Avalanche’s ⅕ of total participants with significantly weaker network assumptions. * _Replacing EC with BFT_: Replacing EC with a BFT protocol (like GossiPBFT) would imply a huge code refactoring, leading to more bugs and significantly more time to develop and productionize the Filecoin upgrade. Furthermore, the combination of EC and F3 is more redundant, ensuring that the system continues operating in the unlikely case that F3 halts. @@ -709,14 +717,14 @@ The modifications proposed in this FIP have far-reaching implications for the se ## Incentive Considerations -Participating in GossiPBFT only entails verifying O(n) and generating O(1) signatures per participant. If not enough participants follow the protocol, the liveness of F3 will be affected. This means that the service offered is affected, but also that participants do not receive rewards from block proposals for the period in which they do not participate. Consequently, we do not believe additional incentives for participation are necessary, as the modifications in this FIP significantly improve the system and the additional computational and communication costs do not substantially alter the cost structure of running a Filecoin node. +Participating in GossiPBFT only entails verifying O(n) and generating O(1) signatures per participant. If not enough participants follow the protocol, the liveness of F3 will be affected. This means that the service offered is affected, but also that participants do not receive rewards from block proposals for the period in which they do not participate. Consequently, we do not believe additional incentives for participation are necessary, as the modifications in this FIP significantly improve the system and the additional computational and communication costs do not substantially alter the cost structure of running a Filecoin node. Furthermore, incentivizing all messages and verification thereof is impossible: this would require consensus on which messages have been sent (which would entail even more messages, these new ones unverified). Nevertheless, subsequent FIPs can provide more incentives, such as rewarding participants whose signatures are listed in agreed-upon PoFs or slash/denylist participants who sign equivocating messages. ## Product Considerations -1. Applications built on FVM and IPC do not need to wait for 900 epochs and can instead benefit from fast finalization times within the order of tens of seconds. +1. Applications built on FVM and IPC do not need to wait for 900 epochs and can instead benefit from fast finalization times within the order of tens of seconds. 2. Other applications built on Filecoin (e.g., Glif, Axelar, Wormhole, exchanges) can also provide fast finality and low latency without compromising security. 3. Safe, verifiable, fast bridging to other networks becomes possible. From fba83e7edb35be9fb0abf624aa1ddbff48692bcd Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 18:28:26 +0100 Subject: [PATCH 03/33] Fix pseudocode --- FIPS/fip-xxxx.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index b23bf99b..167408c5 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -352,22 +352,22 @@ F3(inputChain, baseChain) returns (chain, PoF): 8: while (not decideSent) { 9: if (round = 0) -10: BEBroadcast ; trigger (timeout) -11: collect a clean set M of valid QUALITY messages +10: BEBroadcast ; trigger (timeout) +11: collect a clean set M of valid QUALITY messages until StrongQuorum(proposal, M) OR timeout expires -12: let C={prefix : IsPrefix(prefix,proposal) and StrongQuorum(prefix,M)} -13: if (C = ∅) -14: proposal ← baseChain \* no proposals of high-enough quality -15: else -16: proposal ← heaviest prefix ∈ C \* this becomes baseChain or sth heavier -17: value ← proposal - -18: if (round > 0): \* CONVERGE +12: let C={prefix : IsPrefix(prefix,proposal) and StrongQuorum(prefix,M)} +13: if (C = ∅) +14: proposal ← baseChain \* no proposals of high-enough quality +15: else +16: proposal ← heaviest prefix ∈ C \* this becomes baseChain or sth heavier +17: value ← proposal + +18: if (round > 0) \* CONVERGE 19: ticket ← VRF(Randomness(baseChain) || round) 20: value ← proposal \* set local proposal as value in CONVERGE message 21: BEBroadcast ; trigger(timeout) 22: collect a clean set M of valid CONVERGE msgs from this round - until timeout expires + until timeout expires 23: value ← LowestTicketProposal(M) \* leader election 24: if value ∈ ECCompatibleChains \* see also lines 54-57 25: proposal ← value \* we sway proposal if the value is EC compatible @@ -376,7 +376,7 @@ F3(inputChain, baseChain) returns (chain, PoF): 28: BEBroadcast ; trigger(timeout) 29: collect a clean set M of valid msgs \* match PREPARE value against local proposal - until Power(M) > ⅔ OR timeout expires + until Power(M) > ⅔ OR timeout expires 30: if (Power(M)>⅔) \* strong quorum of PREPAREs for local proposal 31: value ← proposal \* vote for deciding proposal (COMMIT) 32: evidence ← Aggregate(M) \* strong quorum of PREPAREs is evidence @@ -386,10 +386,10 @@ F3(inputChain, baseChain) returns (chain, PoF): 36: BEBroadcast ; trigger(timeout) 37: collect a clean set M of valid COMMIT messages from this round - until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) - OR (timeout expires AND Power(M)>2/3) + until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) + OR (timeout expires AND Power(M)>2/3) 38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide -39: BEBroadcast 0. @@ -451,15 +451,15 @@ AND (∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a stro AND ((∀ m' ∈ M: m'.step = COMMIT AND m'.value = 丄) | of COMMIT msgs for 丄 OR (∀ m' ∈ M: m'.step = PREPARE AND | or PREPARE msgs for m'.value = m.value)) | CONVERGE value - AND (∀ m' ∈ M: m'.round = m.round-1) | from previous round + AND (∀ m' ∈ M: m'.round = m.round-1))) | from previous round OR (m = | valid COMMIT - AND ((∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum - AND ∀ m' ∈ M: m'.step = PREPAR | of PREPARE messages + AND (∃ M: Power(M)>⅔ AND m.evidence=Aggregate(M) | evidence is a strong quorum + AND ∀ m' ∈ M: m'.step = PREPARE | of PREPARE messages AND ∀ m' ∈ M: m'.round = m.round | from the same round AND ∀ m' ∈ M: m'.value = m.value) | for the same value, or - OR (m.value = 丄)) | COMMIT is for 丄 with + OR (m.value = 丄)) | COMMIT is for 丄 with | no evidence ``` From cd3b4c43d145c89d0f7fadca10d3f0394f9cf939 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 23:01:47 +0100 Subject: [PATCH 04/33] Use TeX notation --- FIPS/fip-xxxx.md | 210 +++++++++++++++++++++++------------------------ 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 167408c5..082bb294 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -18,15 +18,15 @@ Filecoin clients currently consider blocks irreversible after 900 epochs, hinder ## Abstract -The current Filecoin consensus mechanism only provides probabilistic finality. To simplify client implementations and provide some form of determinism, the protocol also includes a soft finality threshold, whereby miners at round _N_ reject all blocks that fork off before _N-900_. This finalization delay of 900 epochs (7.5 hours) hinders user experience and limits applications built on Filecoin. +The current Filecoin consensus mechanism only provides probabilistic finality. To simplify client implementations and provide some form of determinism, the protocol also includes a soft finality threshold, whereby miners at round $N$ reject all blocks that fork off before $N-900$. This finalization delay of 900 epochs (7.5 hours) hinders user experience and limits applications built on Filecoin. -We specify a mechanism for fast finality with the F3 component. F3 is expected to finalize tipsets within tens of seconds during regular network operation, compared to the current 900-epoch finalization delay. It does so by leveraging GossiPBFT, an optimally resilient partially synchronous BFT consensus protocol, which runs in parallel with the current protocol, taking EC tipsets as input and providing finalized prefixes as output. EC’s fork choice rule is modified never to select away from the F3-finalized chain. +We specify a mechanism for fast finality with the F3 component. F3 is expected to finalize tipsets within tens of seconds during regular network operation, compared to the current 900-epoch finalization delay. It does so by leveraging GossiPBFT, an optimally resilient partially synchronous BFT consensus protocol, which runs in parallel with the current protocol, taking EC tipsets as input and providing finalized prefixes as output. EC's fork choice rule is modified never to select away from the F3-finalized chain. ## Change Motivation * The long time to finality on Filecoin mainnet restricts or severely affects applications built on Filecoin (e.g., IPC, FVM, Axelar, Wormhole, Glif, …). -* Even though applications on Filecoin can set a lower finalization time than the built-in 900 epochs, delayed finalization for important transactions will require tens of minutes with a longest-chain protocol like Filecoin’s Expected Consensus (EC). +* Even though applications on Filecoin can set a lower finalization time than the built-in 900 epochs, delayed finalization for important transactions will require tens of minutes with a longest-chain protocol like Filecoin's Expected Consensus (EC). * Long finalization times also affect exchanges, by imposing a long confirmation period (often more than 1 hour) for users managing their FIL assets, and bridges, which face extended wait times for asset transfers. * Bridging to other systems is not currently fast, safe, and verifiable. @@ -40,9 +40,9 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t ![](https://hackmd.io/_uploads/Skmdqq6Ip.png) -Two or more tipsets of the same epoch with different parent tipsets (like tipsets _C_ and _C'_ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant _p1_ is not (yet) aware of tipset _D_, it would consider _C_ the heaviest tipset with the canonical chain _[G A B C]_. Another participant _p2_ aware of tipset _D_ will consider _[G A C’ D]_ to be the canonical chain. Once _p1_ becomes aware of tipset _D_, it will update its canonical chain to _[G A C’ D]_ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. +Two or more tipsets of the same epoch with different parent tipsets (like tipsets $C$ and $C'$ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant $p_1$ is not (yet) aware of tipset $D$, it would consider $C$ the heaviest tipset with the canonical chain $[G A B C]$. Another participant $p_2$ aware of tipset $D$ will consider $[G A C' D]$ to be the canonical chain. Once $p_1$ becomes aware of tipset $D$, it will update its canonical chain to $[G A C' D]$ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. -In EC and, generally, longest-chain protocols, the probability of a path from some tipset _h_ to the genesis tipset becoming finalized increases with the number of descendant tipsets of _h_. This happens because the weight of the heaviest chain increases the fastest, as the tipsets with the most new blocks are appended to it (assuming that honest participants form a majority). In the particular case of EC, in each epoch, most created blocks are expected to come from honest participants and thus extend the heaviest chain. Consequently, it becomes progressively harder for a different path to overcome that weight. Over time, the probability of a tipset never undergoing a reorganization becomes high enough that the tipset is considered final for all practical purposes. In the Filecoin network, a tipset that is part of the heaviest chain is considered final after 900 epochs (or, equivalently, 7.5 hours) from its proposal. +In EC and, generally, longest-chain protocols, the probability of a path from some tipset $h$ to the genesis tipset becoming finalized increases with the number of descendant tipsets of $h$. This happens because the weight of the heaviest chain increases the fastest, as the tipsets with the most new blocks are appended to it (assuming that honest participants form a majority). In the particular case of EC, in each epoch, most created blocks are expected to come from honest participants and thus extend the heaviest chain. Consequently, it becomes progressively harder for a different path to overcome that weight. Over time, the probability of a tipset never undergoing a reorganization becomes high enough that the tipset is considered final for all practical purposes. In the Filecoin network, a tipset that is part of the heaviest chain is considered final after 900 epochs (or, equivalently, 7.5 hours) from its proposal. ### F3 Overview and Interaction with EC @@ -51,12 +51,12 @@ We propose implementing fast finality in Filecoin by introducing an F3 component The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage that the SP has committed to the network. This information is maintained in a system actor called the _power table_. -In short, each participant _p_ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds it input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration _i_ (corresponding to the i-th instance of F3): +In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds it input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): -- **EC/F3 interface:** Participant _p_ feeds its current canonical chain _canonical_ and its previously F3-finalized chain, which we call the _baseChain_, to F3. The _baseChain_ defines the power table and seeds randomness used to configure the F3 instance, while _p_'s current canonical chain is the chain _p_ proposes to be finalized. Periodically, _p_ also feeds to F3 tipset updates from EC that extend _p_'s canonical chain as EC delivers these tipsets. -- **F3 consensus:** F3 establishes network-wide consensus on finalized tipsets and produces a _Proof of Finality (PoF)_ for a tipset finalized in instance _i_, _t(i)_. Every _PoF_ output by F3 is signed by ≥ ⅔ of the total QAP, i.e., a super-majority of the power table vouching that honest participants with more than ⅓ QAP consider tipset _t(i)_ final. -- **EC:** Participant _p_ updates its local EC chain and commits not to reorganize the finalized tipset _t(i)_, i.e., the tipset must stay in _p_'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). -- **F3 synchronization:** Participants disseminate information about finalized tipset _t(i)_ and its proof _PoF(i)_ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. +- **EC/F3 interface:** Participant $p$ feeds its current canonical chain $canonical$ and its previously F3-finalized chain, which we call the $baseChain$, to F3. The $baseChain$ defines the power table and seeds randomness used to configure the F3 instance, while $p$'s current canonical chain is the chain $p$ proposes to be finalized. Periodically, $p$ also feeds to F3 tipset updates from EC that extend $p$'s canonical chain as EC delivers these tipsets. +- **F3 consensus:** F3 establishes network-wide consensus on finalized tipsets and produces a _Proof of Finality (PoF)_ for a tipset finalized in instance $i$, $t_i$. Every _PoF_ output by F3 is signed by ≥ ⅔ of the total QAP, i.e., a super-majority of the power table vouching that honest participants with more than ⅓ QAP consider tipset $t_i$ final. +- **EC:** Participant $p$ updates its local EC chain and commits not to reorganize the finalized tipset $t_i$, i.e., the tipset must stay in $p$'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). +- **F3 synchronization:** Participants disseminate information about finalized tipset $t_i$ and its proof $PoF_i$ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. ![](https://hackmd.io/_uploads/r13SXiTU6.png) @@ -64,7 +64,7 @@ In short, each participant _p_ in the Filecoin network (i.e., a storage provider Honest participants follow the protocol at all times. Byzantine participants deviate arbitrarily from the protocol. Rational participants deviate from the protocol to pursue a greater (expected) pay-off according to their utility function. We consider a Byzantine adversary able to control and orchestrate up to less than ⅓ QAP. -We further adapt our protocols to align the actions of honest and rational participants by ensuring that rational participants never contribute to finalizing a chain they do not locally possess. Without this, If a participant _p_ were to finalize a chain it didn’t have, then _p_ would not be able to mine in EC until it retrieved the required blocks and thus, in the meantime, could not obtain the cryptoeconomic rewards that EC offers. To this end, F3 provides _EC incentive compatibility_. +We further adapt our protocols to align the actions of honest and rational participants by ensuring that rational participants never contribute to finalizing a chain they do not locally possess. Without this, If a participant $p$ were to finalize a chain it didn't have, then $p$ would not be able to mine in EC until it retrieved the required blocks and thus, in the meantime, could not obtain the cryptoeconomic rewards that EC offers. To this end, F3 provides _EC incentive compatibility_. F3 and its implementation GossiPBFT provide additional robustness for strong adversaries that control more than ⅓ QAP, such as: @@ -76,15 +76,15 @@ F3 and its implementation GossiPBFT provide additional robustness for strong adv F3 uses GossipSub (like Filecoin EC) to disseminate protocol messages, implementing a broadcast channel among participants. We assume and model GossipSub to satisfy the following properties of the _best-effort broadcast primitive_ (denoted _BEBroadcast_ hereafter): -* If _p_ and _p’_ are honest, then every message broadcast by _p_ is eventually delivered by _p’_. -* No message with sender _p_ is delivered unless it was previously broadcast by _p_. +* If $p$ and $p'$ are honest, then every message broadcast by $p$ is eventually delivered by $p'$. +* No message with sender $p$ is delivered unless it was previously broadcast by $p$. ### Partially Synchronous Model and Δ-Synchrony -We say the system is _Δ-synchronous_ if the combined computation and communication delay between any two honest participants is smaller than _Δ_. We assume that, under _Δ_-synchrony, any message broadcast by an honest participant is delivered by every honest participant within a time bound of _Δ_. +We say the system is $\Delta$-_synchronous_ if the combined computation and communication delay between any two honest participants is smaller than $\Delta$. We assume that, under $\Delta$-synchrony, any message broadcast by an honest participant is delivered by every honest participant within a time bound of $\Delta$. -In practice, if GossipSub is used for _BEBroadcast_, _Δ_ is effectively the assumed upper bound on GossipSub latency (e.g., a few seconds). +In practice, if GossipSub is used for _BEBroadcast_, $\Delta$ is effectively the assumed upper bound on GossipSub latency (e.g., a few seconds). For termination, we assume a classical partially synchronous model with an unknown bound on communication delays among non-Byzantine participants. @@ -101,25 +101,25 @@ With this in mind, the F3 component interface and properties are given below. > > **Properties:** > -> **Agreement.** If two honest participants finalize _(i,h,*)_ and _(i,h’,*)_, then _h_ = _h_’. +> **Agreement.** If two honest participants finalize $(i,h,*)$ and $(i,h',*)$, then $h = h'$. > -> **Validity.** If an honest participant finalizes _(i,h,*)_, then _h_ is a prefix of the canonical input chain of some honest participant _p’_ in instance _i_. +> **Validity.** If an honest participant finalizes $(i,h,*)$, then $h$ is a prefix of the canonical input chain of some honest participant $p'$ in instance $i$. > -> **Proof of Finality.** If an honest participant finalizes _(i,h,PoF)_, then _PoF_ is signed by ⅔ QAP majority corresponding to the _PowerTable(baseChain)’_ input in instance _i_ of some honest participant _p’_. +> **Proof of Finality.** If an honest participant finalizes $(i,h,PoF)$, then $PoF$ is signed by ⅔ QAP majority corresponding to the $\texttt{PowerTable}(baseChain)'$ input in instance $i$ of some honest participant $p'$. > -> **Progress.** If the system is _Δ_-synchronous, i.e., -> * All honest participants can communicate within a known time bound _Δ_, and -> * no honest participants invokes _F3(i, *, *)_ later than _Δ_ after another participant invokes _F3(i, *, *)_, +> **Progress.** If the system is $\Delta$-synchronous, i.e., +> * All honest participants can communicate within a known time bound $\Delta$, and +> * no honest participants invokes $\texttt{F3}(i, *, *)$ later than $\Delta$ after another participant invokes $\texttt{F3}(i, *, *)$, > -> Let c be the heaviest common prefix of the inputs of all honest participants in instance _i_. Then, if an honest participant finalizes _(i,c’,*)_, _c is a prefix of c_’ with probability > 0.5. +> Let c be the heaviest common prefix of the inputs of all honest participants in instance $i$. Then, if an honest participant finalizes $(i,c',*)$, $c$ is a prefix of $c'$ with probability > 0.5. > -> **Termination.** If the system is _Δ_-synchronous, every call to F3 eventually returns with probability _1_. +> **Termination.** If the system is $\Delta$-synchronous, every call to F3 eventually returns with probability 1. > -> **EC Incentive compatibility.** An honest participant never contributes to gathering ⅔ QAP (super-majority) of votes for a chain _c_ which its local EC instance did not already deliver unless it already observes evidence of such a super-majority for chain _c_. +> **EC Incentive compatibility.** An honest participant never contributes to gathering ⅔ QAP (super-majority) of votes for a chain $c$ which its local EC instance did not already deliver unless it already observes evidence of such a super-majority for chain $c$. > -> `F3.ECupdate (int i, chain c)`: Participant _p_ updates F3 instance _i_ with chain _c_, which its EC instance locally delivered (relevant to EC incentive compatibility) +> `F3.ECupdate (int i, chain c)`: Participant $p$ updates F3 instance $i$ with chain $c$, which its EC instance locally delivered (relevant to EC incentive compatibility) -We later show the specific estimate chosen for _Δ_ to optimize termination (See [here](#Synchronization-of-Participants-in-the-Current-Instance)). +We later show the specific estimate chosen for $\Delta$ to optimize termination (See [here](#Synchronization-of-Participants-in-the-Current-Instance)). ### Consensus Interface @@ -132,20 +132,20 @@ We denote the invocation of a consensus instance from a participant as follows: GossiPBFT(i, proposal, participants) → decision, PoF ``` -A participant that invokes the _GossiPBFT()_ function starts a consensus instance identified by the sequence number _i_ and with an input value _proposal_. The _participants_ parameter is composed of the SPs that participate in this instance along with their respective individual weights (i.e., quality-adjusted power). The next section explains how the _participants_ are obtained from the power table. The invocation eventually returns a _decision_ value and a proof of finality _PoF_ that proves _decision_ is indeed the output of this consensus instance. In any invocation from F3, _decision_ is a finalized chain prefix in the form of a tipset. _PoF_ can be verified by using the _Verify()_ function that we explain below: +A participant that invokes the $\texttt{GossiPBFT()}$ function starts a consensus instance identified by the sequence number $i$ and with an input value $proposal$. The $participants$ parameter is composed of the SPs that participate in this instance along with their respective individual weights (i.e., quality-adjusted power). The next section explains how the $participants$ are obtained from the power table. The invocation eventually returns a $decision$ value and a proof of finality $PoF$ that proves $decision$ is indeed the output of this consensus instance. In any invocation from F3, $decision$ is a finalized chain prefix in the form of a tipset. $PoF$ can be verified by using the $\texttt{Verify}()$ function that we explain below: ``` Verify(PoF, decision, participants) → boolean ``` -This function uses the _PoF_ to verify that _decision_ was the output of some instance of consensus executed among the _participants_. +This function uses the $PoF$ to verify that $decision$ was the output of some instance of consensus executed among the $participants$. ### Power Table and Consensus Participants -As mentioned, the _power table_ is a system actor that maintains, among other things, the quality-adjusted power of each SP. Each tipset _t_ in the chain corresponds to a particular version of the power table denoted _PowerTable(t)_ that results from executing all messages in the chain from genesis to _t_. The participants of an instance of GossiPBFT are determined by the power table resulting from the tipset finalized by the previous instance. More rigorously, the input parameter _participants_ of an instance _i_ is obtained from _PowerTable(decisioni-1)_, where _decisioni-1_ is the tipset output by instance _i-1_. If _i_ is the first consensus instance, _decisioni-1_ is the genesis tipset. +As mentioned, the _power table_ is a system actor that maintains, among other things, the quality-adjusted power of each SP. Each tipset $t$ in the chain corresponds to a particular version of the power table denoted $\texttt{PowerTable}(t)$ that results from executing all messages in the chain from genesis to $t$. The participants of an instance of GossiPBFT are determined by the power table resulting from the tipset finalized by the previous instance. More rigorously, the input parameter $participants$ of an instance $i$ is obtained from $\texttt{PowerTable}(decision_{i-1})$, where $decision_{i-1}$ is the tipset output by instance $i-1$. If $i$ is the first consensus instance, $decision_{i-1}$ is the genesis tipset. -We assume that _PowerTable(t)_ ignores any unnecessary data in the power table and returns the set consisting of each participant's identity and weight. +We assume that $\texttt{PowerTable}(t)$ ignores any unnecessary data in the power table and returns the set consisting of each participant's identity and weight. ### F3 Pseudocode @@ -170,16 +170,16 @@ finalizedTipset, PoF ← GossiPBFT(i, proposal, participants) i ← i + 1 ``` -Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named _finalizedTipsets_. It contains one _finalizedTipsets[i]_ entry per consensus instance where _finalizedTipsets[i].tipset_ and _finalizedTipsets[i].PoF_ denote, respectively, the tipset and PoF output by consensus instance _i_. A participant considers a tipset finalized if it is included in _finalizedTipsets_ or is an ancestor of some tipset included in _finalizedTipsets_. +Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named $finalizedTipsets$. It contains one $finalizedTipsets[i]$ entry per consensus instance where $finalizedTipsets[i].tipset$ and $finalizedTipsets[i].PoF$ denote, respectively, the tipset and PoF output by consensus instance $i$. A participant considers a tipset finalized if it is included in $finalizedTipsets$ or is an ancestor of some tipset included in $finalizedTipsets$. -The algorithm starts by initializing _finalizedTipsets[0]_ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration _i_ of the loop, it takes the following steps (see [this document](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit) for details): +The algorithm starts by initializing $finalizedTipsets[0]$ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration $i$ of the loop, it takes the following steps (see [this document](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit) for details): -1. Obtain the set of participants of instance _i_ from the power table determined by the previously finalized tipset. -2. Call the _ChainHead()_ function that returns the head tipset of the locally observed chain constructed by EC and sets the _proposal_ variable to the returned value. We assume that such a function is available to the finalizer. -3. Execute the instance _i_ of GossiPBFT consensus. -4. Add the returned tipset from the consensus execution to the _finalizedTipsets_ list. +1. Obtain the set of participants of instance $i$ from the power table determined by the previously finalized tipset. +2. Call the $\texttt{ChainHead}()$ function that returns the head tipset of the locally observed chain constructed by EC and sets the $proposal$ variable to the returned value. We assume that such a function is available to the finalizer. +3. Execute the instance $i$ of GossiPBFT consensus. +4. Add the returned tipset from the consensus execution to the $finalizedTipsets$ list. -To prevent useless instances of GossiPBFT deciding on the same _baseChain_ because of the lack of a new epoch that provides a new proposal, we make the _ChainHead()_ function blocking in that it does not return a proposal unless (i) the drand epoch value for the epoch immediately following the latest finalized tipset is received and (ii) the current chain head is different from the chain head of the finalized chain. +To prevent useless instances of GossiPBFT deciding on the same $baseChain$ because of the lack of a new epoch that provides a new proposal, we make the $\texttt{ChainHead}()$ function blocking in that it does not return a proposal unless (i) the drand epoch value for the epoch immediately following the latest finalized tipset is received and (ii) the current chain head is different from the chain head of the finalized chain. ### Changes to EC: Fork Choice Rule @@ -188,7 +188,7 @@ EC needs to be modified to accommodate the finalization of tipsets by F3. **This The current EC fork-choice rule selects, from all the known tipsets, the tipset backed by the most weight. As the F3 component finalizes tipsets, the fork-choice rule must ensure that the heaviest finalized chain is always a prefix of the heaviest chain, preventing reorganizations of the already finalized chain. -We achieve this by adjusting the definition of weight for a finalized prefix: the heaviest finalized chain is the one that **matches exactly the tipsets finalized by F3**, in that a tipset _T’_ that is a superset of finalized tipset _T_ in the same epoch is not heavier than _T_ itself, despite it being backed by more EC power. +We achieve this by adjusting the definition of weight for a finalized prefix: the heaviest finalized chain is the one that **matches exactly the tipsets finalized by F3**, in that a tipset $t'$ that is a superset of finalized tipset $t$ in the same epoch is not heavier than $t$ itself, despite it being backed by more EC power. This redefinition of the heaviest chain is consistent with the abstract notion of the heaviest chain being backed by the most power because a finalized tipset has been backed by a super-majority of participants in GossiPBFT. In contrast, any non-finalized block in the same epoch is only backed in that epoch by the EC proposer. @@ -196,12 +196,12 @@ We illustrate the updated rule in the following figure, where blocks in blue are ![](https://hackmd.io/_uploads/SJumBiT8p.png) -The current EC fork-choice rule would select the tipset _{D0, D1}_ as the head of the heaviest chain. However, the heaviest finalized tipset is _{C3}_, which is not an ancestor of _{D0, D1}_. Therefore, the new fork choice rule selects _{D3}_ as the head of the heaviest chain. The reason why _D4_ is not selected is that its parent tipset does not exactly match the finalized tipset _{C3}_, but a superset of it, i.e. _{C3, C4}_. +The current EC fork-choice rule would select the tipset $\{D_0, D_1\}$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\{C_3\}$, which is not an ancestor of $\{D_0, D_1\}$. Therefore, the new fork choice rule selects ${D_3}$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\{C_3\}$, but a superset of it, i.e. $\{C_3, C_4\}$. ### Bootstrapping -Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, _upgradeEpoch_, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the _upgradeEpoch_ minus the 900-epoch lookback as the head tipset of the first _baseChain_, which is assumed by design to be common to all participants. +Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, $upgradeEpoch$, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the $upgradeEpoch$ minus the 900-epoch lookback as the head tipset of the first $baseChain$, which is assumed by design to be common to all participants. ### GossiPBFT Consensus @@ -223,7 +223,7 @@ GossiPBFT was designed with the Filecoin network in mind and presents a set of f #### Message format, signatures, and equivocation -Messages include the following fields: __. As _Round_, _Evidence_, and _Ticket_ are fields that not all message types require, when not required by a message type, their default value is used (i.e. _0_, _AggregatedEvidence{0, []ECTipset{}, 0, 0, []byte{}, []byte{}}_, and _{}_, respectively). We refer to a _field_ of message _m_, with _m.field_: +Messages include the following fields: $\langle Sender, Signature, MsgType, Value, Instance, [Round, Evidence, Ticket] \rangle$. As $Round$, $Evidence$, and $Ticket$ are fields that not all message types require, when not required by a message type, their default value is used (i.e. $0$, $\texttt{AggregatedEvidence}(0, [] ECTipset \{\}, 0, 0, [] byte \{\}, [] byte \{\})$, and $\{\}$, respectively). We refer to a _field_ of message $m$, with $m.field$: ``` type GossiPBFTMessage struct { @@ -285,59 +285,59 @@ type AggregatedEvidence { ``` -All messages broadcast by a participant have their participant ID in the sender field and contain a digital signature by that participant _(m.Signature)_ over _(Instance || MsgType || Value || Round)_. The protocol assumes aggregatable signatures (e.g., BLS, Schnorr), resilient to [rogue public key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html) (see [Boneh, Drijvers, and Neven](https://eprint.iacr.org/2018/483.pdf) construction and [F3 Finality Decision Exchange Protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow) for more details). +All messages broadcast by a participant have their participant ID in the sender field and contain a digital signature by that participant $(m.Signature)$ over $(Instance || MsgType || Value || Round)$. The protocol assumes aggregatable signatures (e.g., BLS, Schnorr), resilient to [rogue public key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html) (see [Boneh, Drijvers, and Neven](https://eprint.iacr.org/2018/483.pdf) construction and [F3 Finality Decision Exchange Protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow) for more details). The receiver of a message only considers messages with valid signatures and discards all other messages as invalid. We sometimes omit the sender IDs and signatures in further descriptions for better readability. -Two (or more) messages _m1_ and _m2_ are called _equivocating messages_ if _m1.Sender=m2.Sender AND m1.Instance=m2.Instance AND m1.Value ≠ m2.Value AND m1.MsgType=m2.MsgType AND (if applicable) m1.Round=m2.Round_. We call _m1.Sender_ an _equivocating sender_. +Two (or more) messages $m1$ and $m2$ are called _equivocating messages_ if $m1.Sender=m2.Sender \land m1.Instance=m2.Instance \land m1.Value ≠ m2.Value \land m1.MsgType=m2.MsgType \land \texttt(if applicable)\ m1.Round=m2.Round$. We call $m1.Sender$ an _equivocating sender_. -A set of messages _M_ that does not contain equivocating messages is called _clean_. Participants discard all equivocating messages when forming clean sets. +A set of messages $M$ that does not contain equivocating messages is called _clean_. Participants discard all equivocating messages when forming clean sets. #### Predicates and functions used in the protocol * `Power(p | P) ∈ [0, 1]` - * Returns the relative QAP of participant _p_ (or set of participants _P_) in EC, defined by the power table corresponding to _baseChain_. The returned value is a fraction of the total QAP of all participants in the power table. + * Returns the relative QAP of participant $p$ (or set of participants $p$) in EC, defined by the power table corresponding to $baseChain$. The returned value is a fraction of the total QAP of all participants in the power table. * `isPrefix(a,b)` - * Returns _True_ if _a_ is a prefix of _b_. (Each chain is also a prefix of itself.) + * Returns $True$ if $a$ is a prefix of $b$. (Each chain is also a prefix of itself.) * `StrongQuorum(prefix,M)` - * Where _M_ is a clean set of messages of the same type and the same round. - * Let _P_ be the set of participants who are senders of messages in _M_ such that their message contains a value with _prefix_ as a prefix. More precisely: + * Where $M$ is a clean set of messages of the same type and the same round. + * Let $p$ be the set of participants who are senders of messages in $M$ such that their message contains a value with $prefix$ as a prefix. More precisely: ``` Let P={p : ∃ m∈ M: m.sender=p AND isPrefix(prefix,m.value)} ``` - then the predicate returns _True_ iff _Power( P )>2/3_ + then the predicate returns $True$ iff $\texttt{Power}(P)>2/3$ * `HasStrongQuorumValue(M)` - * Where _M_ is a clean set of messages of the same type and the same round - * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>2/3_. More precisely: + * Where $M$ is a clean set of messages of the same type and the same round + * The predicate returns $True$ iff there is a value $v$, such that there is a set $p$ of participants who are senders of messages in $M$ such that their message value is exactly $v$ and $\texttt{Power}(P)>2/3$. More precisely: ``` HasStrongQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>2/3 ``` * `StrongQuorumValue(M)` - * Returns _v_ if _HasStrongQuorumValue(M)_ holds, nil otherwise. + * Returns $v$ if $\texttt{HasStrongQuorumValue}(M)$ holds, $nil$ otherwise. * `HasWeakQuorumValue(M)` - * Where _M_ is a clean set of messages of the same type and the same round - * The predicate returns True iff there is a value _v_, such that there is a set _P_ of participants who are senders of messages in _M_ such that their message value is exactly _v_ and _Power( P )>1/3_. More precisely: + * Where $M$ is a clean set of messages of the same type and the same round + * The predicate returns True iff there is a value $v$, such that there is a set $p$ of participants who are senders of messages in $M$ such that their message value is exactly $v$ and $\texttt{Power}(P)>1/3$. More precisely: ``` HasWeakQuorumValue(M) = ∃ v: Power({p : ∃ m∈ M: m.sender=p AND m.value=v})>1/3 ``` * `WeakQuorumValue(M)` - * Returns _v_ if _HasWeakQuorumValue(M)_ holds, nil otherwise. + * Returns $v$ if $\texttt{HasWeakQuorumValue}(M)$ holds, $nil$ otherwise. * `LowestTicketProposal(M)` - * Let _M_ be a clean set of CONVERGE messages for the same round. - * If _M = ∅_, the predicate returns _baseChain_. - * If _M ≠ ∅_, the predicate returns _m.value_, such that _m_ is the message in _M_ with the lowest ticket (_m.ticket_). + * Let $M$ be a clean set of CONVERGE messages for the same round. + * If $M = ∅$, the predicate returns $baseChain$. + * If $M \ne ∅$, the predicate returns $m.value$, such that $m$ is the message in $M$ with the lowest ticket ($m.ticket$). * `Aggregate(M)` - * Where _M_ is a clean set of messages of the same type _T_, round _r_, and instance _i_, with _v=StrongQuorumValue(M)≠nil_. + * Where $M$ is a clean set of messages of the same type $T$, round $r$, and instance $i$, with $v=\texttt{StrongQuorumValue}(M)≠nil$. ``` Let M' ← {m ∈ M : m.value = StrongQuorumValue(M)} ``` - * Returns a tuple __ where _participants_ are all participants such that _m.sender ∈ M'_ (in some compact/compressed representation, i.e. a bitmask with optional run-length encoding) and _agg-sig_ is an aggregate signature (BLS) across all of those participants on _m.i||m.T||m.r||m.v_ for some _m ∈ M'_. + * Returns a tuple $\langle participants, aggSig \rangle$ where $participants$ are all participants such that $m.sender ∈ M'$ (in some compact/compressed representation, i.e. a bitmask with optional run-length encoding) and $aggSig$ is an aggregate signature (BLS) across all of those participants on $(m.i||m.T||m.r||m.v)$ for some $m ∈ M'$. #### GossiPBFT pseudocode (main algorithm) -We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per round (_QUALITY_/_CONVERGE_, _PREPARE_, _COMMIT_) and an additional step outside the round loop (DECIDE). The _Sender_, _Signature_, and _Instance_ fields are omitted from messages for better readability. See also the simplified [PlusCal/TLA+ specification](https://github.com/filecoin-project/f3/blob/main/PlusCal-TLA/GossiPBFT.tla). +We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per round (QUALITY/CONVERGE, PREPARE, COMMIT) and an additional step outside the round loop (DECIDE). The $Sender$, $Signature$, and $Instance$ fields are omitted from messages for better readability. See also the simplified [PlusCal/TLA+ specification](https://github.com/filecoin-project/f3/blob/main/PlusCal-TLA/GossiPBFT.tla). ``` F3(inputChain, baseChain) returns (chain, PoF): @@ -410,7 +410,7 @@ F3(inputChain, baseChain) returns (chain, PoF): 53: go to line 48. ``` -Also, concurrently, we expect that the participant feeds to GossiPBFT chains that are incentive-compatible with EC. To this end, GossiPBFT has a separate invocation called _ECUpdate()_, which is called by an external process at a participant once EC delivers a _chain_ such that _inputChain_ is a prefix of _chain_ (i.e., EC at a participant delivers an extension of _inputChain_). This part is critical to ensuring the progress property in conjunction with lines 24-25. +Also, concurrently, we expect that the participant feeds to GossiPBFT chains that are incentive-compatible with EC. To this end, GossiPBFT has a separate invocation called $\texttt{ECUpdate}()$, which is called by an external process at a participant once EC delivers a $chain$ such that $inputChain$ is a prefix of $chain$ (i.e., EC at a participant delivers an extension of $inputChain$). This part is critical to ensuring the progress property in conjunction with lines 24-25. ``` ECupdate(chain): @@ -421,7 +421,7 @@ ECupdate(chain): #### Valid messages and evidence -The _Valid()_ predicate (referred to in lines 11, 22, 29, 37, and 48) is defined below. +The $\texttt{Valid}()$ predicate (referred to in lines 11, 22, 29, 37, and 48) is defined below. ``` Valid(m): | For a message m to be valid, @@ -441,7 +441,7 @@ If m.step ∈ {CONVERGE, COMMIT} AND | CONVERGE, COMMIT return True ``` -The _ValidEvidence()_ predicate is defined below (for other definitions used below, see [Preliminaries](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.ygq5svj4e7ap)). Note that _QUALITY_, _PREPARE_ and _DECIDE_ messages do not need evidence. In fact, _DECIDE_ does not need any protocol-specific validation, since a weak quorum of _DECIDE_ with the same value is required to trigger any execution of the protocol. +The $\texttt{ValidEvidence}()$ predicate is defined below (for other definitions used below, see [Preliminaries](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.ygq5svj4e7ap)). Note that QUALITY, PREPARE and DECIDE messages do not need evidence. In fact, DECIDE does not need any protocol-specific validation, since a weak quorum of DECIDE with the same value is required to trigger any execution of the protocol. ``` ValidEvidence(m): @@ -464,39 +464,39 @@ OR (m = | valid COMMIT ``` ### Evidence verification complexity -Note that during the validation of each CONVERGE and COMMIT message, two signatures need to be verified: (1) the signature of the message contents, produced by the sender of the message (first check above) and (2) the aggregate signature in _m.evidence_ (_ValidEvidence(m)_ above). The former can be verified using the sender’s public key (stored in the power table). The latter, being an aggregated signature, requires aggregating public keys of all the participants whose signatures it combines. Notice that the evidence of each message can be signed by a different set of participants, which requires aggregating a linear number of public BLS keys (in system size) per evidence verification. +Note that during the validation of each CONVERGE and COMMIT message, two signatures need to be verified: (1) the signature of the message contents, produced by the sender of the message (first check above) and (2) the aggregate signature in $m.evidence$ ($\texttt{ValidEvidence}(m)$ above). The former can be verified using the sender's public key (stored in the power table). The latter, being an aggregated signature, requires aggregating public keys of all the participants whose signatures it combines. Notice that the evidence of each message can be signed by a different set of participants, which requires aggregating a linear number of public BLS keys (in system size) per evidence verification. However, a participant only needs to verify the evidence once for each *unique* message (in terms of (step, round, value)) received. Moreover, verification can further be reduced to those messages a participant uses to make progress (such as advancing to the next step or deciding), ignoring the rest as they are not needed for progress. This reduces the number of evidence verifications in each step to at most one. #### Randomness -An instance of GossiPBFT requires a seed σ that must be common among all participants due to the dependency on a VRF in the _CONVERGE_ step. As only one random seed is required per GossiPBFT instance, and there is only one GossiPBFT instance per epoch (see below), the random seed for GossiPBFT can be sourced from drand’s output for that epoch in EC. +An instance of GossiPBFT requires a seed σ that must be common among all participants due to the dependency on a VRF in the CONVERGE step. As only one random seed is required per GossiPBFT instance, and there is only one GossiPBFT instance per epoch (see below), the random seed for GossiPBFT can be sourced from drand's output for that epoch in EC. ### Synchronization of Participants in the Current Instance -GossiPBFT ensures termination provided that (i) all participants start the instance at most _Δ_ apart, and (ii) the estimate on Δ is large enough for _Δ_-synchrony in some round (either because of the real network delay recovering from asynchrony or because of the estimate increasing). +GossiPBFT ensures termination provided that (i) all participants start the instance at most $\Delta$ apart, and (ii) the estimate on Δ is large enough for $\Delta$-synchrony in some round (either because of the real network delay recovering from asynchrony or because of the estimate increasing). -[Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within _Δ=3s_, with a huge majority receiving them even after _Δ=2s_. However, if several participants start the instance _Δ + ε_ after some other participants, termination is not guaranteed for the selected timeouts of _2*Δ_. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. +[Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within $Δ=3s$, with a huge majority receiving them even after $Δ=2s$. However, if several participants start the instance $Δ + ε$ after some other participants, termination is not guaranteed for the selected timeouts of $2*Δ$. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. The synchronization of participants is performed in the call to updateTimeout(timeout, round) (line 46), and works as follows: -* Participants start an instance with Δ=2s. -* If the first and second rounds fail to reach termination, participants start the 3rd round with Δ=3s. +* Participants start an instance with $Δ=2s$. +* If the first and second rounds fail to reach termination, participants start the 3rd round with $Δ=3s$. * If 5 rounds fail to reach termination (rounds from 0 to 4), participants wait to receive the next drand epoch value to start round 5. This ensures that a potential ε delay between when participants started the instance is not carried over beyond round 4. -* If round 5 fails to reach a decision, participants set exponential timeout increase Δ= 1.3*Δ for every failed round. This ensures termination even if the real network delay increases arbitrarily. +* If round 5 fails to reach a decision, participants set exponential timeout increase $Δ= 1.3*Δ$ for every failed round. This ensures termination even if the real network delay increases arbitrarily. -Additionally, as an optimization, participants could continue to the subsequent step once the execution of the current step has been determined, without waiting for the timeout. For example, if a participant receives _QUALITY_ messages from all participants, it can proceed to the next step without waiting for the timeout. More generally, if the remaining valid messages to be received cannot change the execution of the step, regardless of the values contained in the messages, then a participant should continue to the next step. +Additionally, as an optimization, participants could continue to the subsequent step once the execution of the current step has been determined, without waiting for the timeout. For example, if a participant receives QUALITY messages from all participants, it can proceed to the next step without waiting for the timeout. More generally, if the remaining valid messages to be received cannot change the execution of the step, regardless of the values contained in the messages, then a participant should continue to the next step. ### Synchronization of Participants across Instances -The _finalizedTipsets_ data structure is disseminated among the participants and other observers of the Filecoin network in the same manner as the chain itself. In particular, newly joined and temporarily disconnected participants and observers wishing to download and verify the chain can obtain the _finalizedTipsets_ data from other participants or observers (see [main design document](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.gxmabiz2hh3k) for details). +The $finalizedTipsets$ data structure is disseminated among the participants and other observers of the Filecoin network in the same manner as the chain itself. In particular, newly joined and temporarily disconnected participants and observers wishing to download and verify the chain can obtain the $finalizedTipsets$ data from other participants or observers (see [main design document](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.gxmabiz2hh3k) for details). To verify a finality decision, assuming prior knowledge of an already-final base, a client needs: * The power table entries from the base -* A set of signed _DECIDE_ messages for that base that agree on the same value, from distinct senders comprising more than ⅔ QAP in the base +* A set of signed DECIDE messages for that base that agree on the same value, from distinct senders comprising more than ⅔ QAP in the base * The public keys for those signers A finality certificate brings them together. @@ -529,7 +529,7 @@ A finality certificate is analogous to a full block in the EC block exchange pro #### Exchange protocol -Like with EC block exchange, participants follow **a simple request/response protocol to provide a contiguous sequence of finality certificates**. Note that the sequence of certificates is traversed backward, matching block exchange. A finality certificate contains the tipset and the PoF of the tipset (_Signature_). PoFs may vary across participants, but all PoFs must be for the same tipset at the same instance number _i_. +Like with EC block exchange, participants follow **a simple request/response protocol to provide a contiguous sequence of finality certificates**. Note that the sequence of certificates is traversed backward, matching block exchange. A finality certificate contains the tipset and the PoF of the tipset ($Signature$). PoFs may vary across participants, but all PoFs must be for the same tipset at the same instance number $i$. ``` type Request struct { @@ -550,12 +550,12 @@ type Response struct { #### Certificate verification -The client’s algorithm to verify a finality certificate is roughly: +The client's algorithm to verify a finality certificate is roughly: * Check that the instance number and base tipset follow from the previous certificate * Load the power and public key for each sender from the base power table * Verify that the sum of the power of signers exceeds ⅔ of the total power in the table -* Compute the _GossiPBFTMessage_ corresponding to a _DECIDE_ by each sender +* Compute the _GossiPBFTMessage_ corresponding to a DECIDE by each sender * Verify the BLS aggregate signature against the list of messages and keys Further, a client prepares to verify the next finality certificate by: @@ -570,9 +570,9 @@ Certificate verification must bottom out in some genesis certificate, which is a **A verifier needs each signer's power and public key** (GossiPBFT also needs these for its execution). These are provided by the power table associated with each finalized tipset. -Assuming some genesis tipset with a known power table, a _GossiPBFTMessage_ can provide a commitment to (CID of) the resulting power table but doesn’t provide the actual entries. A finality certificate includes these as a delta from the previous power table. A verifier can compute the power table for the subsequent certificate by applying these deltas to its base power table. +Assuming some genesis tipset with a known power table, a _GossiPBFTMessage_ can provide a commitment to (CID of) the resulting power table but doesn't provide the actual entries. A finality certificate includes these as a delta from the previous power table. A verifier can compute the power table for the subsequent certificate by applying these deltas to its base power table. -Note the power table deltas don’t need to be signed. All _DECIDE_ messages include a commitment to the CID of the resulting power table. Hence, a verifier only needs to confirm that the power table CID as a result of their computation matches that committed to by the signed messages. A finality certificate with incorrect power table deltas cannot be used as a base to verify subsequent instances. +Note the power table deltas don't need to be signed. All DECIDE messages include a commitment to the CID of the resulting power table. Hence, a verifier only needs to confirm that the power table CID as a result of their computation matches that committed to by the signed messages. A finality certificate with incorrect power table deltas cannot be used as a base to verify subsequent instances. #### Verification by Filecoin node (“fast catch-up”) @@ -608,7 +608,7 @@ Many possibilities were considered for faster finality. We justify the architect * _Improvements to Filecoin's EC_: Longest chain protocols rely on the increasing probability over time that some state is consistent across all participants. In all existing implementations of longest-chain protocols, finalization thus incurs at least tens of minutes. * _Best-effort finality gadgets_: Ethereum's approach to faster finality involves the introduction of a novel finality gadget. However, this finality gadget requires at least two epochs for finalization, translating to at least more than 30 seconds in Filecoin. In contrast, GossiPBFT can achieve sub-epoch finalization and is only limited by the network speed. Moreover, Ethereum's protocol is yet to be proven correct. In fact, multiple attacks have been described in the literature that show how an adversary can keep the system from ever finalizing blocks, even after fixes. -* _Sub-sample voting_: Avalanche’s sub-sample voting copes with arbitrarily large groups of participants by repeatedly sub-sampling constant-size subsets. Unfortunately, Avalanche's strong network assumptions make the protocol vulnerable to an adversary exploiting network delays. Moreover, Avalanche ensures correctness against an adversary controlling at most ⅕ of participants, versus ⅓ targeted by GossiPBFT. Even when GossiPBFT becomes amenable to committees, for reasonable committees of 600 participants, GossiPBFT already tolerates Avalanche’s ⅕ of total participants with significantly weaker network assumptions. +* _Sub-sample voting_: Avalanche's sub-sample voting copes with arbitrarily large groups of participants by repeatedly sub-sampling constant-size subsets. Unfortunately, Avalanche's strong network assumptions make the protocol vulnerable to an adversary exploiting network delays. Moreover, Avalanche ensures correctness against an adversary controlling at most ⅕ of participants, versus ⅓ targeted by GossiPBFT. Even when GossiPBFT becomes amenable to committees, for reasonable committees of 600 participants, GossiPBFT already tolerates Avalanche's ⅕ of total participants with significantly weaker network assumptions. * _Replacing EC with BFT_: Replacing EC with a BFT protocol (like GossiPBFT) would imply a huge code refactoring, leading to more bugs and significantly more time to develop and productionize the Filecoin upgrade. Furthermore, the combination of EC and F3 is more redundant, ensuring that the system continues operating in the unlikely case that F3 halts. @@ -626,21 +626,21 @@ Because of changes to the EC fork choice rule, this FIP requires a network upgra ## Test Cases 1. Unit tests -2. Test propagation times during network load to set an estimate on _Δ_ +2. Test propagation times during network load to set an estimate on $\Delta$ 1. 3.5k participants sending messages of size >120B over GossipSub (and measure time to receive first, a strong quorum, and all messages). - 2. Same test but for _DECIDE_ messages (which include the passive nodes, not just participants, in the corresponding GossipSub topic). + 2. Same test but for DECIDE messages (which include the passive nodes, not just participants, in the corresponding GossipSub topic). 3. Protocol-specific tests: - Correctness tests (synchrony is assumed for tests unless stated otherwise): * Best case: all participants start with the same input. - Expected Behavior (EB): all participants decide in round 1. - * No synchrony: all participants start with the same input but there is no synchrony at first (less than ⅔ QAP receive the _QUALITY_ messages on time from the rest). Synchrony is restored only after _QUALITY_ finishes. - - EB: all participants decide _baseChain_. - * No quality: participants holding <⅔ QAP start GossiPBFT with a chain _c_ and the rest with a chain _c'_, such that _c_ and _c'_ only share _baseChain_ as prefix. - - EB: all participants decide _baseChain_. - * Prefix quality: participants holding <⅔ QAP start GossiPBFT with a chain _c_ and the rest with a chain _c'_, such that _c_ and _c'_ share some prefix _c''_ that extends _baseChain_. - - EB: all participants decide _c''_. - * Decision of different participants in different rounds: three different partitions, _P_, _Q_, _T_ start with different input chains _c_, _c'_, _c''_, such that _c_ is a prefix of _c'_, and _c'_ of _c''_, respectively, (they strictly extend each other, none being baseChain). QAP of Q >½, while that of _P_ and _T_ are equally split. There is no synchrony between _P_ and _T_ until the beginning of the second round. - - EB: The first round results in participants in _P_ voting for _c_, the rest voting for _c'_ and deciding _c'_. At the start of the second round, once synchrony is restored, _P_ also decides _c'_. + * No synchrony: all participants start with the same input but there is no synchrony at first (less than ⅔ QAP receive the QUALITY messages on time from the rest). Synchrony is restored only after QUALITY finishes. + - EB: all participants decide $baseChain$. + * No quality: participants holding <⅔ QAP start GossiPBFT with a chain $c$ and the rest with a chain $c'$, such that $c$ and $c'$ only share $baseChain$ as prefix. + - EB: all participants decide $baseChain$. + * Prefix quality: participants holding <⅔ QAP start GossiPBFT with a chain $c$ and the rest with a chain $c'$, such that $c$ and $c'$ share some prefix $c''$ that extends $baseChain$. + - EB: all participants decide $c''$. + * Decision of different participants in different rounds: three different partitions, $P$, $Q$, $T$ start with different input chains $c$, $c'$, $c''$, such that $c$ is a prefix of $c'$, and $c'$ of $c''$, respectively, (they strictly extend each other, none being baseChain). QAP of $Q$ >½, while that of $P$ and $T$ are equally split. There is no synchrony between $p$ and $T$ until the beginning of the second round. + - EB: The first round results in participants in $P$ voting for $c$, the rest voting for $c'$ and deciding $c'$. At the start of the second round, once synchrony is restored, $P$ also decides $c'$. * Membership-change: - New participants (>⅓ QAP) join the power table and catch up to the latest instance. - EB: Successful catch-up to the currently executed instance and decision in this instance. @@ -663,36 +663,36 @@ Because of changes to the EC fork choice rule, this FIP requires a network upgra - Evidence insufficient by QAP according to the corresponding power table. * Invalid value - Value not extending the corresponding baseChain - - Value not being acceptable (after _QUALITY_ step) + - Value not being acceptable (after QUALITY step) - Tests under faults: * Crashing: - <⅓ QAP does not send any message from the beginning; the rest share the same input. - EB: the common input is decided in the first round. - - \>⅔ QAP send _QUALITY_ messages for some chain _c_, while the rest for some chain _c'_ (_c_ and _c'_ only share _baseChain_ as common prefix). After sending _QUALITY_ messages, participants that sent _c_ and that hold <⅓ QAP crash. - - EB: c is decided (participants that sent _c'_ swayed to _c_) in the first round. - - Same setup as the test with [three different partitions](#three-partitions), but participants holding less than ⅓ QAP in Q crash after sending _QUALITY_. One more participant (still in total <⅓ QAP), holding the lowest ticket, crashes in the second round right after sending its _CONVERGE_. - - EB: the chain voted by the crashed participant (i.e., _c'_) is decided. + - \>⅔ QAP send QUALITY messages for some chain $c$, while the rest for some chain $c'$ ($c$ and $c'$ only share $baseChain$ as common prefix). After sending QUALITY messages, participants that sent $c$ and that hold <⅓ QAP crash. + - EB: $c$ is decided (participants that sent $c'$ swayed to $c$) in the first round. + - Same setup as the test with [three different partitions](#three-partitions), but participants holding less than ⅓ QAP in Q crash after sending QUALITY. One more participant (still in total <⅓ QAP), holding the lowest ticket, crashes in the second round right after sending its CONVERGE. + - EB: the chain voted by the crashed participant (i.e., $c'$) is decided. * Crash-recovery: - Repeat tests and their EB when, at a given moment, all participants crash and recover (can be done on smaller scales) - Make tests for crashes at different points of the protocol through fuzzing * Equivocating: - - Three partitions, _F_ holding <⅓ QAP, _P_ and _Q_ holding the rest of QAP (with _P_ holding more QAP than _Q_). Participants in P do not receive messages from Q timely, and vice versa, in the first round. Participants in _F_ send _QUALITY_ for _c_ to _P_ and _QUALITY_ for _c'_ to _P'_. They do the same with _PREPARE_, _PROPOSE_, _COMMIT_. Synchrony is restored in round 2. - - EB: in the first round, participants in _P_ decide _c_. Participants in _Q_ go to round 2, where they also decide _c_. Participants in _F_ are detected as equivocating by _P_ and _Q_ eventually. - - Same setup as the test with [three different partitions](#three-partitions), but participants holding just less than ⅓ QAP in _Q_ equivocate after sending _QUALITY_ by sending _PREPARE_ and _PROPOSE_ for _c_ to _P_ and for _c'_ to honest participants in _Q_ and _T_. - - EB: honest participants in _Q_ and _T_ decide _c'_ in the first round. Once synchrony is restored in the second round, participants in _P_ decide _c'_ too (perhaps subject to the lower ticket being held by non-Byzantine). + - Three partitions, $F$ holding <⅓ QAP, $P$ and $Q$ holding the rest of QAP (with $P$ holding more QAP than $Q$). Participants in $P$ do not receive messages from $Q$ timely, and vice versa, in the first round. Participants in $F$ send QUALITY for $c$ to $P$ and QUALITY for $c'$ to _P'_. They do the same with PREPARE, PROPOSE, COMMIT. Synchrony is restored in round 2. + - EB: in the first round, participants in $P$ decide $c$. Participants in $Q$ go to round 2, where they also decide $c$. Participants in $F$ are detected as equivocating by $p$ and $Q$ eventually. + - Same setup as the test with [three different partitions](#three-partitions), but participants holding just less than ⅓ QAP in $Q$ equivocate after sending QUALITY by sending PREPARE and PROPOSE for $c$ to $P$ and for $c'$ to honest participants in $Q$ and $T$. + - EB: honest participants in $Q$ and $T$ decide $c'$ in the first round. Once synchrony is restored in the second round, participants in $P$ decide $c'$ too (perhaps subject to the lower ticket being held by non-Byzantine). - Flooding messages for future instances/rounds - - Participants holding <⅓ QAP keep sending _QUALITY_ and _PREPARE_ messages for future rounds/instances (as they do not require evidence), intending to flood memory. + - Participants holding <⅓ QAP keep sending QUALITY and PREPARE messages for future rounds/instances (as they do not require evidence), intending to flood memory. - EB: the system can handle buffering a large load of future messages. - Participants proposing chains that do not extend base chain (EB for all these is that these messages are discarded as the value is invalid): - - Superset (chain proposed includes the _baseChain_ head tipset but not exactly the head tipset) - - Subset (chain proposed contains a tipset included by the _baseChain_ head tipset but not exactly the head tipset) + - Superset (chain proposed includes the $baseChain$ head tipset but not exactly the head tipset) + - Subset (chain proposed contains a tipset included by the $baseChain$ head tipset but not exactly the head tipset) - Disjoint tipset - Non-liveness of GossiPBFT for 900 epochs or more. The setup for this is >⅓ QAP crash. - Expected behavior: - EC finalizes tipsets - Honest participants do not participate anymore to finalize anything (handbrake) 4. Integration tests: - - Test 0th instance: all participants start by assuming _baseChain_ is epoch number (_upgradeEpoch_ minus 900). + - Test 0th instance: all participants start by assuming $baseChain$ is epoch number ($upgradeEpoch$ minus 900). - EB: F3 successfully bootstraps with a decision. - Test under Byzantine behavior (<⅓ QAP) and network delays. - Test upgrade: same as above, but perform a test in calibration (or simulated upgrade), not in isolation (as above). @@ -708,7 +708,7 @@ Because of changes to the EC fork choice rule, this FIP requires a network upgra The modifications proposed in this FIP have far-reaching implications for the security of the system. This FIP changes Filecoin at a fundamental level: from considering tipsets as final after some time to finalizing them after a quorum of participants reach an agreement. We list here the security considerations this modification entails. -* **Censorship.** F3 and GossiPBFT are designed with censorship resistance in mind. The updated fork choice rule means that an adversary controlling at least more than ⅓ QAP can try to perform a censorship attack if honest participants start an instance of GossiPBFT proposing at least two distinct inputs. While this attack is theoretically possible, it is notably hard to perform on F3 given the _QUALITY_ step of GossiPBFT and other mitigation strategies specifically put in place to protect against this (See [GossipBFT's design document, Appendix B](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.3563x64us9fj) for more details on the attack and mitigations). We strongly believe that, even against a majority adversary, the mitigations designed will prevent such an attack. +* **Censorship.** F3 and GossiPBFT are designed with censorship resistance in mind. The updated fork choice rule means that an adversary controlling at least more than ⅓ QAP can try to perform a censorship attack if honest participants start an instance of GossiPBFT proposing at least two distinct inputs. While this attack is theoretically possible, it is notably hard to perform on F3 given the QUALITY step of GossiPBFT and other mitigation strategies specifically put in place to protect against this (See [GossipBFT's design document, Appendix B](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.3563x64us9fj) for more details on the attack and mitigations). We strongly believe that, even against a majority adversary, the mitigations designed will prevent such an attack. * **Liveness.** Implementing F3 introduces the risk that an adversary controlling at least ⅓ QAP prevents termination of a GossiPBFT instance. In that case, the F3 component would halt, not finalizing any tipset anymore. At the same time, EC would still operate, outputting tipsets and considering them final after 900 epochs (see [Fast Finality in Filecoin (F3), Appendix A](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit#heading=h.iwwgfqxud6bn) for more details). The liveness of the system is thus not affected by attacks on the liveness of F3. * **Safety.** Implementing F3 ensures the safety of finalized outputs during regular or even congested networks against a Byzantine adversary controlling less than ⅓ QAP. For stronger adversaries, F3 provides mitigations to prevent censorship attacks, as outlined above. If deemed necessary, the punishment and recovery from coalitions in the event of an attempted attack on safety can be explored in future FIPs. Note that safety is already significantly improved by F3 compared to the status quo: F3 provides safety of finalized outputs two orders of magnitude faster than the current estimate of 900 epochs during regular network operation. * **Denial-of-service (DoS).** The implementation of the F3 preserves resistance against DoS attacks currently ensured by Filecoin, thanks to the fully leaderless nature of GossiPBFT and to the use of a VRF to self-assign tickets during the CONVERGE step. @@ -717,7 +717,7 @@ The modifications proposed in this FIP have far-reaching implications for the se ## Incentive Considerations -Participating in GossiPBFT only entails verifying O(n) and generating O(1) signatures per participant. If not enough participants follow the protocol, the liveness of F3 will be affected. This means that the service offered is affected, but also that participants do not receive rewards from block proposals for the period in which they do not participate. Consequently, we do not believe additional incentives for participation are necessary, as the modifications in this FIP significantly improve the system and the additional computational and communication costs do not substantially alter the cost structure of running a Filecoin node. +Participating in GossiPBFT only entails verifying $O(n)$ and generating $O(1)$ signatures per participant. If not enough participants follow the protocol, the liveness of F3 will be affected. This means that the service offered is affected, but also that participants do not receive rewards from block proposals for the period in which they do not participate. Consequently, we do not believe additional incentives for participation are necessary, as the modifications in this FIP significantly improve the system and the additional computational and communication costs do not substantially alter the cost structure of running a Filecoin node. Furthermore, incentivizing all messages and verification thereof is impossible: this would require consensus on which messages have been sent (which would entail even more messages, these new ones unverified). Nevertheless, subsequent FIPs can provide more incentives, such as rewarding participants whose signatures are listed in agreed-upon PoFs or slash/denylist participants who sign equivocating messages. From ce3e68026339945f8e953eda2796ada9499e0330 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 23:05:36 +0100 Subject: [PATCH 05/33] Fix agreement rendering --- FIPS/fip-xxxx.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 082bb294..29b3f239 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -101,17 +101,17 @@ With this in mind, the F3 component interface and properties are given below. > > **Properties:** > -> **Agreement.** If two honest participants finalize $(i,h,*)$ and $(i,h',*)$, then $h = h'$. +> **Agreement.** If two honest participants finalize $(i,h,\ast)$ and $(i,h',\ast)$, then $h = h'$. > -> **Validity.** If an honest participant finalizes $(i,h,*)$, then $h$ is a prefix of the canonical input chain of some honest participant $p'$ in instance $i$. +> **Validity.** If an honest participant finalizes $(i,h,\ast)$, then $h$ is a prefix of the canonical input chain of some honest participant $p'$ in instance $i$. > > **Proof of Finality.** If an honest participant finalizes $(i,h,PoF)$, then $PoF$ is signed by ⅔ QAP majority corresponding to the $\texttt{PowerTable}(baseChain)'$ input in instance $i$ of some honest participant $p'$. > > **Progress.** If the system is $\Delta$-synchronous, i.e., > * All honest participants can communicate within a known time bound $\Delta$, and -> * no honest participants invokes $\texttt{F3}(i, *, *)$ later than $\Delta$ after another participant invokes $\texttt{F3}(i, *, *)$, +> * no honest participants invokes $\texttt{F3}(i, \ast, \ast)$ later than $\Delta$ after another participant invokes $\texttt{F3}(i, \ast, \ast)$, > -> Let c be the heaviest common prefix of the inputs of all honest participants in instance $i$. Then, if an honest participant finalizes $(i,c',*)$, $c$ is a prefix of $c'$ with probability > 0.5. +> Let c be the heaviest common prefix of the inputs of all honest participants in instance $i$. Then, if an honest participant finalizes $(i,c',\ast)$, $c$ is a prefix of $c'$ with probability > 0.5. > > **Termination.** If the system is $\Delta$-synchronous, every call to F3 eventually returns with probability 1. > From ed3ef3761a65a38e0729d27ae3546b34e1e3d3a4 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 19 Dec 2023 23:13:16 +0100 Subject: [PATCH 06/33] Format fix --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 29b3f239..8344aef6 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -208,7 +208,7 @@ Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One e This section provides the specification of GossiPBFT, the consensus protocol that is iteratively instantiated by the F3 loop and returns a decision (in the form of an F3-finalized chain) and a PoF per instance. -GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the **final** decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent (see [main design document](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit) for details). +GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the final decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent (see [main design document](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit) for details). GossiPBFT was designed with the Filecoin network in mind and presents a set of features that make it desirable in that context: From 2629d55c242da5b446541be5f920aacc15ad891d Mon Sep 17 00:00:00 2001 From: Alejandro Ranchal-Pedrosa Date: Wed, 20 Dec 2023 12:48:15 +0100 Subject: [PATCH 07/33] Update fip-xxxx.md (#894) Fixed up brackets not showing --- FIPS/fip-xxxx.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 8344aef6..da42aefb 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -196,7 +196,7 @@ We illustrate the updated rule in the following figure, where blocks in blue are ![](https://hackmd.io/_uploads/SJumBiT8p.png) -The current EC fork-choice rule would select the tipset $\{D_0, D_1\}$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\{C_3\}$, which is not an ancestor of $\{D_0, D_1\}$. Therefore, the new fork choice rule selects ${D_3}$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\{C_3\}$, but a superset of it, i.e. $\{C_3, C_4\}$. +The current EC fork-choice rule would select the tipset $\lbrace D_0, D_1\rbrace$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\lbrace C_3\rbrace$, which is not an ancestor of $\lbrace D_0, D_1\rbrace$. Therefore, the new fork choice rule selects $\lbrace D_3\rbrace$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\lbrace C_3\rbrace$, but a superset of it, i.e. $\lbrace C_3, C_4\rbrace$. ### Bootstrapping @@ -223,7 +223,7 @@ GossiPBFT was designed with the Filecoin network in mind and presents a set of f #### Message format, signatures, and equivocation -Messages include the following fields: $\langle Sender, Signature, MsgType, Value, Instance, [Round, Evidence, Ticket] \rangle$. As $Round$, $Evidence$, and $Ticket$ are fields that not all message types require, when not required by a message type, their default value is used (i.e. $0$, $\texttt{AggregatedEvidence}(0, [] ECTipset \{\}, 0, 0, [] byte \{\}, [] byte \{\})$, and $\{\}$, respectively). We refer to a _field_ of message $m$, with $m.field$: +Messages include the following fields: $\langle Sender, Signature, MsgType, Value, Instance, [Round, Evidence, Ticket] \rangle$. As $Round$, $Evidence$, and $Ticket$ are fields that not all message types require, when not required by a message type, their default value is used (i.e. $0$, $\texttt{AggregatedEvidence}(0, [] ECTipset \lbrace\rbrace, 0, 0, [] byte \lbrace\rbrace, [] byte \lbrace\rbrace)$, and $[] byte \lbrace\rbrace$, respectively). We refer to a _field_ of message $m$, with $m.field$: ``` type GossiPBFTMessage struct { From a007ad1fa43e9d5c02967fb99ce8a782421344a9 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Wed, 20 Dec 2023 22:16:01 +0100 Subject: [PATCH 08/33] Move images into repo --- FIPS/fip-xxxx.md | 6 +++--- resources/fip-xxxx/chain.png | Bin 0 -> 102299 bytes resources/fip-xxxx/flow.png | Bin 0 -> 53126 bytes resources/fip-xxxx/fork.png | Bin 0 -> 78835 bytes 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 resources/fip-xxxx/chain.png create mode 100644 resources/fip-xxxx/flow.png create mode 100644 resources/fip-xxxx/fork.png diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index da42aefb..de8ba6f1 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -38,7 +38,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t [Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. -![](https://hackmd.io/_uploads/Skmdqq6Ip.png) +![](../resources/fip-xxxx/chain.png) Two or more tipsets of the same epoch with different parent tipsets (like tipsets $C$ and $C'$ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant $p_1$ is not (yet) aware of tipset $D$, it would consider $C$ the heaviest tipset with the canonical chain $[G A B C]$. Another participant $p_2$ aware of tipset $D$ will consider $[G A C' D]$ to be the canonical chain. Once $p_1$ becomes aware of tipset $D$, it will update its canonical chain to $[G A C' D]$ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. @@ -58,7 +58,7 @@ In short, each participant $p$ in the Filecoin network (i.e., a storage provider - **EC:** Participant $p$ updates its local EC chain and commits not to reorganize the finalized tipset $t_i$, i.e., the tipset must stay in $p$'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). - **F3 synchronization:** Participants disseminate information about finalized tipset $t_i$ and its proof $PoF_i$ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. -![](https://hackmd.io/_uploads/r13SXiTU6.png) +![](../resources/fip-xxxx/flow.png) ### F3 Adversarial Model @@ -194,7 +194,7 @@ This redefinition of the heaviest chain is consistent with the abstract notion o We illustrate the updated rule in the following figure, where blocks in blue are finalized blocks, and all blocks are assumed to be proposed by a proposer holding only one EC ticket (the weight of a chain is the number of blocks): -![](https://hackmd.io/_uploads/SJumBiT8p.png) +![](../resources/fip-xxxx/fork.png) The current EC fork-choice rule would select the tipset $\lbrace D_0, D_1\rbrace$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\lbrace C_3\rbrace$, which is not an ancestor of $\lbrace D_0, D_1\rbrace$. Therefore, the new fork choice rule selects $\lbrace D_3\rbrace$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\lbrace C_3\rbrace$, but a superset of it, i.e. $\lbrace C_3, C_4\rbrace$. diff --git a/resources/fip-xxxx/chain.png b/resources/fip-xxxx/chain.png new file mode 100644 index 0000000000000000000000000000000000000000..555294fa86b53e564fbc4f8cf02754fb55d15f4e GIT binary patch literal 102299 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 Co_QSr literal 0 HcmV?d00001 diff --git a/resources/fip-xxxx/flow.png b/resources/fip-xxxx/flow.png new file mode 100644 index 0000000000000000000000000000000000000000..820ef5edbb751b30cb36a2e2a6d101ba09da3139 GIT binary patch literal 53126 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 V@e=tU96{0EiGwr>O1a}&`ckhh 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 literal 0 HcmV?d00001 diff --git a/resources/fip-xxxx/fork.png b/resources/fip-xxxx/fork.png new file mode 100644 index 0000000000000000000000000000000000000000..791b1a4cc3408a67e4b84f461ec9ac6c24d98686 GIT binary patch literal 78835 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 z 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 literal 0 HcmV?d00001 From 02181a62c2640882dd2fe0cf0412efa2d600699d Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Thu, 21 Dec 2023 00:40:37 +0100 Subject: [PATCH 09/33] Remove links --- FIPS/fip-xxxx.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index de8ba6f1..db6b6848 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -91,7 +91,7 @@ For termination, we assume a classical partially synchronous model with an unkno ### Properties of F3 -F3 is not identical to classical consensus, however similar to it. In a nutshell, the reasons why EC and Filecoin should not rely on classical consensus properties (implemented by existing off-the-shelf BFT consensus protocol) for fast finality are twofold: EC incentive compatibility and resilience to Filecoin power leakage attacks in case of a strong adversary. We refer to the accompanying document [Appendix A: F3 requirements specific to Filecoin and EC](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.jg4hdeovc1zg) for more details. +F3 is not identical to classical consensus, however similar to it. In a nutshell, the reasons why EC and Filecoin should not rely on classical consensus properties (implemented by existing off-the-shelf BFT consensus protocol) for fast finality are twofold: EC incentive compatibility and resilience to Filecoin power leakage attacks in case of a strong adversary. With this in mind, the F3 component interface and properties are given below. @@ -172,7 +172,7 @@ finalizedTipset, PoF ← GossiPBFT(i, proposal, participants) Each participant keeps track of the finalized tipsets and respective proofs of finality in a data structure named $finalizedTipsets$. It contains one $finalizedTipsets[i]$ entry per consensus instance where $finalizedTipsets[i].tipset$ and $finalizedTipsets[i].PoF$ denote, respectively, the tipset and PoF output by consensus instance $i$. A participant considers a tipset finalized if it is included in $finalizedTipsets$ or is an ancestor of some tipset included in $finalizedTipsets$. -The algorithm starts by initializing $finalizedTipsets[0]$ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration $i$ of the loop, it takes the following steps (see [this document](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit) for details): +The algorithm starts by initializing $finalizedTipsets[0]$ with the genesis tipset. This tipset is pre-defined as finalized and does not require a PoF. Then, in each iteration $i$ of the loop, it takes the following steps: 1. Obtain the set of participants of instance $i$ from the power table determined by the previously finalized tipset. 2. Call the $\texttt{ChainHead}()$ function that returns the head tipset of the locally observed chain constructed by EC and sets the $proposal$ variable to the returned value. We assume that such a function is available to the finalizer. @@ -208,7 +208,7 @@ Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One e This section provides the specification of GossiPBFT, the consensus protocol that is iteratively instantiated by the F3 loop and returns a decision (in the form of an F3-finalized chain) and a PoF per instance. -GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the final decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent (see [main design document](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit) for details). +GossiPBFT is a Byzantine fault-tolerant consensus protocol that is resilient optimal, i.e., it tolerates up to less than ⅓ QAP being controlled by a Byzantine adversary. Each instance of the protocol has a known set of participants. Each participant inputs a proposal value, and the protocol outputs one of the input values as the final decision value. We emphasize _final_ because, unlike a longest-chain protocol, the output of GossiPBFT is permanent. GossiPBFT was designed with the Filecoin network in mind and presents a set of features that make it desirable in that context: @@ -285,7 +285,7 @@ type AggregatedEvidence { ``` -All messages broadcast by a participant have their participant ID in the sender field and contain a digital signature by that participant $(m.Signature)$ over $(Instance || MsgType || Value || Round)$. The protocol assumes aggregatable signatures (e.g., BLS, Schnorr), resilient to [rogue public key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html) (see [Boneh, Drijvers, and Neven](https://eprint.iacr.org/2018/483.pdf) construction and [F3 Finality Decision Exchange Protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow) for more details). +All messages broadcast by a participant have their participant ID in the sender field and contain a digital signature by that participant $(m.Signature)$ over $(Instance || MsgType || Value || Round)$. The protocol assumes aggregatable signatures (e.g., BLS, Schnorr), resilient to [rogue public key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html) (see [Boneh, Drijvers, and Neven](https://eprint.iacr.org/2018/483.pdf) construction). The receiver of a message only considers messages with valid signatures and discards all other messages as invalid. We sometimes omit the sender IDs and signatures in further descriptions for better readability. @@ -337,7 +337,7 @@ A set of messages $M$ that does not contain equivocating messages is called _cle #### GossiPBFT pseudocode (main algorithm) -We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per round (QUALITY/CONVERGE, PREPARE, COMMIT) and an additional step outside the round loop (DECIDE). The $Sender$, $Signature$, and $Instance$ fields are omitted from messages for better readability. See also the simplified [PlusCal/TLA+ specification](https://github.com/filecoin-project/f3/blob/main/PlusCal-TLA/GossiPBFT.tla). +We illustrate the pseudocode for GossiPBFT below, consisting of 3 steps per round (QUALITY/CONVERGE, PREPARE, COMMIT) and an additional step outside the round loop (DECIDE). The $Sender$, $Signature$, and $Instance$ fields are omitted from messages for better readability. See also the simplified [PlusCal/TLA+ specification](https://github.com/filecoin-project/tla-f3). ``` F3(inputChain, baseChain) returns (chain, PoF): @@ -441,7 +441,7 @@ If m.step ∈ {CONVERGE, COMMIT} AND | CONVERGE, COMMIT return True ``` -The $\texttt{ValidEvidence}()$ predicate is defined below (for other definitions used below, see [Preliminaries](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.ygq5svj4e7ap)). Note that QUALITY, PREPARE and DECIDE messages do not need evidence. In fact, DECIDE does not need any protocol-specific validation, since a weak quorum of DECIDE with the same value is required to trigger any execution of the protocol. +The $\texttt{ValidEvidence}()$ predicate is defined below. Note that QUALITY, PREPARE and DECIDE messages do not need evidence. In fact, DECIDE does not need any protocol-specific validation, since a weak quorum of DECIDE with the same value is required to trigger any execution of the protocol. ``` ValidEvidence(m): @@ -491,7 +491,7 @@ Additionally, as an optimization, participants could continue to the subsequent ### Synchronization of Participants across Instances -The $finalizedTipsets$ data structure is disseminated among the participants and other observers of the Filecoin network in the same manner as the chain itself. In particular, newly joined and temporarily disconnected participants and observers wishing to download and verify the chain can obtain the $finalizedTipsets$ data from other participants or observers (see [main design document](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.gxmabiz2hh3k) for details). +The $finalizedTipsets$ data structure is disseminated among the participants and other observers of the Filecoin network in the same manner as the chain itself. In particular, newly joined and temporarily disconnected participants and observers wishing to download and verify the chain can obtain the $finalizedTipsets$ data from other participants or observers. To verify a finality decision, assuming prior knowledge of an already-final base, a client needs: @@ -708,8 +708,8 @@ Because of changes to the EC fork choice rule, this FIP requires a network upgra The modifications proposed in this FIP have far-reaching implications for the security of the system. This FIP changes Filecoin at a fundamental level: from considering tipsets as final after some time to finalizing them after a quorum of participants reach an agreement. We list here the security considerations this modification entails. -* **Censorship.** F3 and GossiPBFT are designed with censorship resistance in mind. The updated fork choice rule means that an adversary controlling at least more than ⅓ QAP can try to perform a censorship attack if honest participants start an instance of GossiPBFT proposing at least two distinct inputs. While this attack is theoretically possible, it is notably hard to perform on F3 given the QUALITY step of GossiPBFT and other mitigation strategies specifically put in place to protect against this (See [GossipBFT's design document, Appendix B](https://docs.google.com/document/d/17FBkZzrVWZg2zmq3JJcSZdn7MfbAPC9Lv2FgG42omxo/edit#heading=h.3563x64us9fj) for more details on the attack and mitigations). We strongly believe that, even against a majority adversary, the mitigations designed will prevent such an attack. -* **Liveness.** Implementing F3 introduces the risk that an adversary controlling at least ⅓ QAP prevents termination of a GossiPBFT instance. In that case, the F3 component would halt, not finalizing any tipset anymore. At the same time, EC would still operate, outputting tipsets and considering them final after 900 epochs (see [Fast Finality in Filecoin (F3), Appendix A](https://docs.google.com/document/d/1FzTNGG0N00RP80X0ARSmdUQLwe2iCS-EwxMrhAhqCbw/edit#heading=h.iwwgfqxud6bn) for more details). The liveness of the system is thus not affected by attacks on the liveness of F3. +* **Censorship.** F3 and GossiPBFT are designed with censorship resistance in mind. The updated fork choice rule means that an adversary controlling at least more than ⅓ QAP can try to perform a censorship attack if honest participants start an instance of GossiPBFT proposing at least two distinct inputs. While this attack is theoretically possible, it is notably hard to perform on F3 given the QUALITY step of GossiPBFT and other mitigation strategies specifically put in place to protect against this. We strongly believe that, even against a majority adversary, the mitigations designed will prevent such an attack. +* **Liveness.** Implementing F3 introduces the risk that an adversary controlling at least ⅓ QAP prevents termination of a GossiPBFT instance. In that case, the F3 component would halt, not finalizing any tipset anymore. At the same time, EC would still operate, outputting tipsets and considering them final after 900 epochs. The liveness of the system is thus not affected by attacks on the liveness of F3. * **Safety.** Implementing F3 ensures the safety of finalized outputs during regular or even congested networks against a Byzantine adversary controlling less than ⅓ QAP. For stronger adversaries, F3 provides mitigations to prevent censorship attacks, as outlined above. If deemed necessary, the punishment and recovery from coalitions in the event of an attempted attack on safety can be explored in future FIPs. Note that safety is already significantly improved by F3 compared to the status quo: F3 provides safety of finalized outputs two orders of magnitude faster than the current estimate of 900 epochs during regular network operation. * **Denial-of-service (DoS).** The implementation of the F3 preserves resistance against DoS attacks currently ensured by Filecoin, thanks to the fully leaderless nature of GossiPBFT and to the use of a VRF to self-assign tickets during the CONVERGE step. * **Committees.** This FIP proposes to have all participants run all instances of GossiPBFT. While this ensures optimal resilience against a Byzantine adversary, it can render the system unusable if the number of participants grows too large. While we are still evaluating the maximum practical number of participants in F3, it is expected to be at least one order of magnitude greater than the current number of participants in Filecoin. This introduces an attack vector: if the scalability limit is 100,000 participants, a participant holding as little as 3% of the current QAP can perform a Sybil attack to render the system unusable, with the minimum QAP required per identity. As a result, the implementation should favor the messages of the more powerful participants if the number of participants grows too large. Given that favoring more powerful participants discriminates against the rest, affecting decentralization, amending F3 to use committees in the event of the number of participants exceeding the practical limit will be the topic of a future FIP, as well as the analysis of optimized message aggregation in the presence of self-selected committees. From d26f04e20498d7a7448a4e475fa77f12b2cc343e Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Thu, 21 Dec 2023 00:54:46 +0100 Subject: [PATCH 10/33] Add TODO --- FIPS/fip-xxxx.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index db6b6848..2cfa9dd1 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -733,6 +733,15 @@ Furthermore, incentivizing all messages and verification thereof is impossible: We refer to the stand-alone implementation in a simulated environment in the [go-f3](https://github.com/filecoin-project/go-f3) repository. Work is ongoing on a reference lotus implementation (to be provided soon). + +## TODO + +- [ ] Complete benchmarking around message complexity and computational/networking requirements. +- [ ] Decide between implicit and explicit evidence, based on forthcoming. +- [ ] Finalize and incorporate the WIP [finality exchange protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow). +- [ ] Update and move supplemental documentation into `resources` + + ## Copyright Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From 8d3ef98c7611fd7f8b04d1b3867d0167b2e73ee4 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Thu, 21 Dec 2023 01:10:48 +0100 Subject: [PATCH 11/33] Minor updates --- FIPS/fip-xxxx.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 2cfa9dd1..e94ba5b2 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -737,9 +737,9 @@ We refer to the stand-alone implementation in a simulated environment in the [go ## TODO - [ ] Complete benchmarking around message complexity and computational/networking requirements. -- [ ] Decide between implicit and explicit evidence, based on forthcoming. +- [ ] Decide between implicit and explicit evidence, taking into account benchmark results. - [ ] Finalize and incorporate the WIP [finality exchange protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow). -- [ ] Update and move supplemental documentation into `resources` +- [ ] Update and move proofs of correctness and other supplemental documentation into `resources` ## Copyright From 836d06463279f9977a6d247d6a16a19ff25c9d39 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:23:08 +0100 Subject: [PATCH 12/33] Update FIPS/fip-xxxx.md Co-authored-by: Matej Pavlovic --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index e94ba5b2..69b5f089 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -402,7 +402,7 @@ F3(inputChain, baseChain) returns (chain, PoF): 48: collect a clean set M of DECIDE messages until (HasStrongQuorumValue(M)) \* Collect a strong quorum of decide outside the round loop -49: return (StrongQuorumValue(M)) +49: return (StrongQuorumValue(M), Aggregate(M)) 50: upon reception of clean set M of DECIDE messages such that HasWeakQuorumValue(M) and not decideSent 51: decideSent ← True From 9ad97ce63e4d37b60ed9077ecc0941a08b521e39 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:14:23 +0000 Subject: [PATCH 13/33] Update authors --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 69b5f089..589e0942 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -1,7 +1,7 @@ --- fip: "" title: Fast Finality in Filecoin -author: Jie Hou (@mb1896), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) +author: Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 status: Draft type: Technical From a7c0471f39314ca184511336f0ec35923860208b Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:52:07 +0100 Subject: [PATCH 14/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 589e0942..b7fd9b0f 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -1,6 +1,6 @@ --- fip: "" -title: Fast Finality in Filecoin +title: Fast Finality in Filecoin (F3) author: Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 status: Draft From 0bfd35c8d5e6ea30391e3765f5cc147b091e760d Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:52:43 +0100 Subject: [PATCH 15/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index b7fd9b0f..881df37b 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -25,7 +25,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t ## Change Motivation -* The long time to finality on Filecoin mainnet restricts or severely affects applications built on Filecoin (e.g., IPC, FVM, Axelar, Wormhole, Glif, …). +* The long time to finality on Filecoin mainnet restricts or severely affects applications built on Filecoin (e.g., IPC, Axelar, Wormhole, Glif, …). * Even though applications on Filecoin can set a lower finalization time than the built-in 900 epochs, delayed finalization for important transactions will require tens of minutes with a longest-chain protocol like Filecoin's Expected Consensus (EC). * Long finalization times also affect exchanges, by imposing a long confirmation period (often more than 1 hour) for users managing their FIL assets, and bridges, which face extended wait times for asset transfers. * Bridging to other systems is not currently fast, safe, and verifiable. From 1b6c30d1b905b8d4df264bbb906a4dc2fa32de66 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:56:24 +0100 Subject: [PATCH 16/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 881df37b..347a48b2 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -36,7 +36,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t ### Background -[Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. +[Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become block proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. ![](../resources/fip-xxxx/chain.png) From ce2f48c695e95f013a6809daffb07f4ff0c8dd0b Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 21:57:23 +0100 Subject: [PATCH 17/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 347a48b2..eb873684 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -49,7 +49,7 @@ In EC and, generally, longest-chain protocols, the probability of a path from so We propose implementing fast finality in Filecoin by introducing an F3 component, which works alongside EC in Filecoin client nodes (participants). -The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage that the SP has committed to the network. This information is maintained in a system actor called the _power table_. +The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage power that the SP has committed to the network. This information is maintained in a built-in actor called the _power actor_ (f04). In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds it input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): From 64543be415bfdc385eb66e716786d97e3c65180d Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:16:22 +0100 Subject: [PATCH 18/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index eb873684..c039accb 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -51,7 +51,7 @@ We propose implementing fast finality in Filecoin by introducing an F3 component The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage power that the SP has committed to the network. This information is maintained in a built-in actor called the _power actor_ (f04). -In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds it input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): +In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds its input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): - **EC/F3 interface:** Participant $p$ feeds its current canonical chain $canonical$ and its previously F3-finalized chain, which we call the $baseChain$, to F3. The $baseChain$ defines the power table and seeds randomness used to configure the F3 instance, while $p$'s current canonical chain is the chain $p$ proposes to be finalized. Periodically, $p$ also feeds to F3 tipset updates from EC that extend $p$'s canonical chain as EC delivers these tipsets. - **F3 consensus:** F3 establishes network-wide consensus on finalized tipsets and produces a _Proof of Finality (PoF)_ for a tipset finalized in instance $i$, $t_i$. Every _PoF_ output by F3 is signed by ≥ ⅔ of the total QAP, i.e., a super-majority of the power table vouching that honest participants with more than ⅓ QAP consider tipset $t_i$ final. From c9d8a5dc35ce133623afe48b0f6f61c94647a5d2 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:16:35 +0100 Subject: [PATCH 19/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index c039accb..b1afa013 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -20,7 +20,7 @@ Filecoin clients currently consider blocks irreversible after 900 epochs, hinder The current Filecoin consensus mechanism only provides probabilistic finality. To simplify client implementations and provide some form of determinism, the protocol also includes a soft finality threshold, whereby miners at round $N$ reject all blocks that fork off before $N-900$. This finalization delay of 900 epochs (7.5 hours) hinders user experience and limits applications built on Filecoin. -We specify a mechanism for fast finality with the F3 component. F3 is expected to finalize tipsets within tens of seconds during regular network operation, compared to the current 900-epoch finalization delay. It does so by leveraging GossiPBFT, an optimally resilient partially synchronous BFT consensus protocol, which runs in parallel with the current protocol, taking EC tipsets as input and providing finalized prefixes as output. EC's fork choice rule is modified never to select away from the F3-finalized chain. +We specify a mechanism for fast finality with the F3 component. F3 is expected to finalize tipsets within tens of seconds during regular network operation, compared to the current 900-epoch finalization delay. It does so by leveraging GossiPBFT, an optimally resilient partially synchronous BFT consensus protocol, which runs in parallel with the current protocol, taking EC tipsets as input and providing finalized prefixes as output. The fork choice rule of EC is modified to ensure it never selects a chain other than the F3-finalized chain. ## Change Motivation From f3564189d11817328168c9e75a80ff5f7292ba13 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 9 Jan 2024 23:51:49 +0100 Subject: [PATCH 20/33] Mention the power threshold --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index b1afa013..347c2613 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -49,7 +49,7 @@ In EC and, generally, longest-chain protocols, the probability of a path from so We propose implementing fast finality in Filecoin by introducing an F3 component, which works alongside EC in Filecoin client nodes (participants). -The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage power that the SP has committed to the network. This information is maintained in a built-in actor called the _power actor_ (f04). +The participants in F3 are the storage providers (SPs) of the Filecoin network. The participation of each SP is weighted according to its quality-adjusted power (QAP), which is a function of the storage power that the SP has committed to the network. This information is maintained in a built-in actor called the _power actor_ (f04). Only SPs that hold more than the threshold of power to participate in EC can participate in F3. In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds its input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): From 0b699611314bb43ba4abf0b548065d690b62707e Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:16:11 +0100 Subject: [PATCH 21/33] Update FIPS/fip-xxxx.md Co-authored-by: Matej Pavlovic --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 347c2613..86ca3c94 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -389,7 +389,7 @@ F3(inputChain, baseChain) returns (chain, PoF): until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) OR (timeout expires AND Power(M)>2/3) 38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide -39: BEBroadcast 40: decideSent ← True 40: if (∃ m ∈ M: m.value ≠ 丄) \* m.value was possibly decided by others 41: proposal ← m.value; \* sway local proposal to possibly decided value From 00786d850808c9540b27f92ceb97c09896cdf479 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:03:13 +0100 Subject: [PATCH 22/33] Update FIPS/fip-xxxx.md Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 86ca3c94..22b4f201 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -143,7 +143,7 @@ This function uses the $PoF$ to verify that $decision$ was the output of some in ### Power Table and Consensus Participants -As mentioned, the _power table_ is a system actor that maintains, among other things, the quality-adjusted power of each SP. Each tipset $t$ in the chain corresponds to a particular version of the power table denoted $\texttt{PowerTable}(t)$ that results from executing all messages in the chain from genesis to $t$. The participants of an instance of GossiPBFT are determined by the power table resulting from the tipset finalized by the previous instance. More rigorously, the input parameter $participants$ of an instance $i$ is obtained from $\texttt{PowerTable}(decision_{i-1})$, where $decision_{i-1}$ is the tipset output by instance $i-1$. If $i$ is the first consensus instance, $decision_{i-1}$ is the genesis tipset. +The _power table_ in the power actor maintains, among other things, the quality-adjusted power of each SP. Each tipset $t$ in the chain corresponds to a particular version of the power table denoted $\texttt{PowerTable}(t)$ that results from executing all messages in the chain from genesis to $t$. The participants of an instance of GossiPBFT are determined by the power table resulting from the tipset finalized by the previous instance. More rigorously, the input parameter $participants$ of an instance $i$ is obtained from $\texttt{PowerTable}(decision_{i-1})$, where $decision_{i-1}$ is the tipset output by instance $i-1$. If $i$ is the first consensus instance, $decision_{i-1}$ is the genesis tipset. We assume that $\texttt{PowerTable}(t)$ ignores any unnecessary data in the power table and returns the set consisting of each participant's identity and weight. From d3926bef61a4b5f5cf35ba4b45a1dfdeab4ec952 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:06:56 +0100 Subject: [PATCH 23/33] Address @jennijuju's comment --- FIPS/fip-xxxx.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 22b4f201..b5cd047d 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -53,9 +53,9 @@ The participants in F3 are the storage providers (SPs) of the Filecoin network. In short, each participant $p$ in the Filecoin network (i.e., a storage provider with power) runs F3 in a loop and feeds its input from EC. F3 returns a finalized prefix chain to EC, which updates the canonical chain to extend this F3-finalized prefix. More precisely, in each loop iteration $i$ (corresponding to the i-th instance of F3): -- **EC/F3 interface:** Participant $p$ feeds its current canonical chain $canonical$ and its previously F3-finalized chain, which we call the $baseChain$, to F3. The $baseChain$ defines the power table and seeds randomness used to configure the F3 instance, while $p$'s current canonical chain is the chain $p$ proposes to be finalized. Periodically, $p$ also feeds to F3 tipset updates from EC that extend $p$'s canonical chain as EC delivers these tipsets. +- **EC/F3 interface:** Participant $p$ feeds its current canonical chain $canonical$ and its previously F3-finalized chain, which we call the $baseChain$, to F3. The $baseChain$ defines the power table **used by F3** and seeds the randomness used to configure the F3 instance, while $p$'s current canonical chain is the chain $p$ proposes to be finalized. Periodically, $p$ also feeds to F3 tipset updates from EC that extend $p$'s canonical chain as EC delivers these tipsets. - **F3 consensus:** F3 establishes network-wide consensus on finalized tipsets and produces a _Proof of Finality (PoF)_ for a tipset finalized in instance $i$, $t_i$. Every _PoF_ output by F3 is signed by ≥ ⅔ of the total QAP, i.e., a super-majority of the power table vouching that honest participants with more than ⅓ QAP consider tipset $t_i$ final. -- **EC:** Participant $p$ updates its local EC chain and commits not to reorganize the finalized tipset $t_i$, i.e., the tipset must stay in $p$'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). +- **EC:** Participant $p$ updates its local EC chain and commits not to reorganize the finalized tipset $t_i$, i.e., the tipset must stay in $p$'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table (which can therefore differ from the one used by F3) and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). - **F3 synchronization:** Participants disseminate information about finalized tipset $t_i$ and its proof $PoF_i$ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. ![](../resources/fip-xxxx/flow.png) From fe9073b86dd1bcd0ed146dae0abf3bc384fead7f Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Wed, 24 Jan 2024 01:22:52 +0100 Subject: [PATCH 24/33] Update todo --- FIPS/fip-xxxx.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index b5cd047d..f864372b 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -736,8 +736,8 @@ We refer to the stand-alone implementation in a simulated environment in the [go ## TODO -- [ ] Complete benchmarking around message complexity and computational/networking requirements. -- [ ] Decide between implicit and explicit evidence, taking into account benchmark results. +- [x] Complete benchmarking around message complexity and computational/networking requirements. +- [x] Decide between implicit and explicit evidence, taking into account benchmark results. - [ ] Finalize and incorporate the WIP [finality exchange protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow). - [ ] Update and move proofs of correctness and other supplemental documentation into `resources` From 794ae7d4f5fede5effc64e88ea610ce85f70925a Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Wed, 24 Jan 2024 01:23:24 +0100 Subject: [PATCH 25/33] Update title --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index f864372b..fdf0bcce 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -9,7 +9,7 @@ category: Core created: 2023-12-18 --- -# Fast Finality in Filecoin +# Fast Finality in Filecoin (F3) ## Simple Summary From 40fa4f1b2fae4688a3a6ddad5276c17adba595dd Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Wed, 24 Jan 2024 18:19:19 +0100 Subject: [PATCH 26/33] Clarify bootstrap --- FIPS/fip-xxxx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index fdf0bcce..8415f5fb 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -201,7 +201,7 @@ The current EC fork-choice rule would select the tipset $\lbrace D_0, D_1\rbrace ### Bootstrapping -Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, $upgradeEpoch$, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance with the tipset at the $upgradeEpoch$ minus the 900-epoch lookback as the head tipset of the first $baseChain$, which is assumed by design to be common to all participants. +Integrating F3 into Filecoin follows the usual path for Filecoin upgrades. One epoch, $upgradeEpoch$, will be defined as the target epoch upon which participants upgrade Filecoin. Then, every participant starts the first instance of F3 with the tipset at the $upgradeEpoch$ minus the 900-epoch lookback as the head tipset of the first $baseChain$, which is assumed by design to be common to all participants. ### GossiPBFT Consensus From f538418529e7002c507ed7e5c108cecb975921b7 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Thu, 25 Jan 2024 00:37:28 +0100 Subject: [PATCH 27/33] Update FIPS/fip-xxxx.md --- FIPS/fip-xxxx.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 8415f5fb..5d49b038 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -198,6 +198,8 @@ We illustrate the updated rule in the following figure, where blocks in blue are The current EC fork-choice rule would select the tipset $\lbrace D_0, D_1\rbrace$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\lbrace C_3\rbrace$, which is not an ancestor of $\lbrace D_0, D_1\rbrace$. Therefore, the new fork choice rule selects $\lbrace D_3\rbrace$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\lbrace C_3\rbrace$, but a superset of it, i.e. $\lbrace C_3, C_4\rbrace$. +In the event that F3 halts, the fork choice rule allows EC to continue to progress, building a chain of unbounded length, per the current rules, on the last F3-finalized prefix. + ### Bootstrapping From 8b90d016fbf6ce867ca18fc45e9acef76988452a Mon Sep 17 00:00:00 2001 From: Alejandro Ranchal-Pedrosa Date: Mon, 29 Jan 2024 16:04:00 -0300 Subject: [PATCH 28/33] Update fip-xxxx.md (#932) Remove Bracha amplification of DECIDE and use explicit justification (to reflect final adjustment to protocol as per go-f3). --- FIPS/fip-xxxx.md | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-xxxx.md index 5d49b038..019c9758 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-xxxx.md @@ -371,7 +371,7 @@ F3(inputChain, baseChain) returns (chain, PoF): 22: collect a clean set M of valid CONVERGE msgs from this round until timeout expires 23: value ← LowestTicketProposal(M) \* leader election -24: if value ∈ ECCompatibleChains \* see also lines 54-57 +24: if value ∈ ECCompatibleChains \* see also lines 55-56 25: proposal ← value \* we sway proposal if the value is EC compatible 26: else 27: value ← 丄 \* vote for not deciding in this round @@ -391,25 +391,26 @@ F3(inputChain, baseChain) returns (chain, PoF): until (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) OR (timeout expires AND Power(M)>2/3) 38: if (HasStrongQuorumValue(M) AND StrongQuorumValue(M) ≠ 丄) \* decide -39: BEBroadcast +39: evidence ← Aggregate(M) +39: BEBroadcast 40: decideSent ← True -40: if (∃ m ∈ M: m.value ≠ 丄) \* m.value was possibly decided by others -41: proposal ← m.value; \* sway local proposal to possibly decided value -42: evidence ← m.evidence \* strong PREPARE quorum is inherited evidence -43: else \* no participant decided in this round -44: evidence ← Aggregate(M) \* strong quorum of COMMITs for 丄 is evidence -45: round ← round + 1; -46: timeout ← updateTimeout(timeout, round) -47: } \*end while - -48: collect a clean set M of DECIDE messages +41: if (∃ m ∈ M: m.value ≠ 丄) \* m.value was possibly decided by others +42: proposal ← m.value; \* sway local proposal to possibly decided value +43: evidence ← m.evidence \* strong PREPARE quorum is inherited evidence +44: else \* no participant decided in this round +45: evidence ← Aggregate(M) \* strong quorum of COMMITs for 丄 is evidence +46: round ← round + 1; +47: timeout ← updateTimeout(timeout, round) +48: } \*end while + +49: collect a clean set M of DECIDE messages until (HasStrongQuorumValue(M)) \* Collect a strong quorum of decide outside the round loop -49: return (StrongQuorumValue(M), Aggregate(M)) +50: return (StrongQuorumValue(M), Aggregate(M)) -50: upon reception of clean set M of DECIDE messages such that HasWeakQuorumValue(M) and not decideSent -51: decideSent ← True -52: BEBroadcast message and not decideSent +52: decideSent ← True +53: BEBroadcast +54: go to line 49 ``` Also, concurrently, we expect that the participant feeds to GossiPBFT chains that are incentive-compatible with EC. To this end, GossiPBFT has a separate invocation called $\texttt{ECUpdate}()$, which is called by an external process at a participant once EC delivers a $chain$ such that $inputChain$ is a prefix of $chain$ (i.e., EC at a participant delivers an extension of $inputChain$). This part is critical to ensuring the progress property in conjunction with lines 24-25. @@ -417,13 +418,13 @@ Also, concurrently, we expect that the participant feeds to GossiPBFT chains tha ``` ECupdate(chain): -54: If (IsPrefix(proposal, chain)) \* sanity check -55: ECCompatibleChains ← ECCompatibleChains ∪ all prefixes of chain, not lighter than baseChain +55: If (IsPrefix(proposal, chain)) \* sanity check +56: ECCompatibleChains ← ECCompatibleChains ∪ all prefixes of chain, not lighter than baseChain ``` #### Valid messages and evidence -The $\texttt{Valid}()$ predicate (referred to in lines 11, 22, 29, 37, and 48) is defined below. +The $\texttt{Valid}()$ predicate (referred to in lines 11, 22, 29, 37, and 49) is defined below. ``` Valid(m): | For a message m to be valid, @@ -481,7 +482,7 @@ GossiPBFT ensures termination provided that (i) all participants start the insta [Given prior tests performed on GossipSub](https://research.protocol.ai/publications/gossipsub-v1.1-evaluation-report/vyzovitis2020.pdf) (see also [here](https://gist.github.com/jsoares/9ce4c0ba6ebcfd2afa8f8993890e2d98)), we expect that almost all participants will reach sent messages within $Δ=3s$, with a huge majority receiving them even after $Δ=2s$. However, if several participants start the instance $Δ + ε$ after some other participants, termination is not guaranteed for the selected timeouts of $2*Δ$. Thus, we do not rely on an explicit synchrony bound for correctness. Instead, we (i) use drand as a beacon to synchronize participants within an instance and (ii) increase the estimate of Δ locally within an instance as rounds progress without decision. -The synchronization of participants is performed in the call to updateTimeout(timeout, round) (line 46), and works as follows: +The synchronization of participants is performed in the call to updateTimeout(timeout, round) (line 47), and works as follows: * Participants start an instance with $Δ=2s$. * If the first and second rounds fail to reach termination, participants start the 3rd round with $Δ=3s$. From d4bb694344c9aa640ffbb85d8156f3aac5049d40 Mon Sep 17 00:00:00 2001 From: Kaitlin Beegle <46908964+kaitlin-beegle@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:50:55 -0800 Subject: [PATCH 29/33] Update and rename fip-xxxx.md to fip-0086.md Updated to add FIP number --- FIPS/{fip-xxxx.md => fip-0086.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename FIPS/{fip-xxxx.md => fip-0086.md} (99%) diff --git a/FIPS/fip-xxxx.md b/FIPS/fip-0086.md similarity index 99% rename from FIPS/fip-xxxx.md rename to FIPS/fip-0086.md index 019c9758..1c04d6f5 100644 --- a/FIPS/fip-xxxx.md +++ b/FIPS/fip-0086.md @@ -1,5 +1,5 @@ --- -fip: "" +fip: "0086" title: Fast Finality in Filecoin (F3) author: Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 From 1d835beaf02c81dc2a2897937597c065c1161841 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:54:42 +0100 Subject: [PATCH 30/33] Update fip number --- FIPS/fip-0086.md | 8 ++++---- resources/{fip-xxxx => fip-0086}/chain.png | Bin resources/{fip-xxxx => fip-0086}/flow.png | Bin resources/{fip-xxxx => fip-0086}/fork.png | Bin 4 files changed, 4 insertions(+), 4 deletions(-) rename resources/{fip-xxxx => fip-0086}/chain.png (100%) rename resources/{fip-xxxx => fip-0086}/flow.png (100%) rename resources/{fip-xxxx => fip-0086}/fork.png (100%) diff --git a/FIPS/fip-0086.md b/FIPS/fip-0086.md index 1c04d6f5..940452b7 100644 --- a/FIPS/fip-0086.md +++ b/FIPS/fip-0086.md @@ -38,7 +38,7 @@ We specify a mechanism for fast finality with the F3 component. F3 is expected t [Expected Consensus (EC)](https://spec.filecoin.io/algorithms/expected_consensus/) is the current mechanism by which participants in the Filecoin network reach an agreement on tipsets. A tipset is a set of blocks with the same epoch and the same set of parents. EC is a longest-chain protocol (more accurately, a heaviest-chain protocol) in which each participant independently builds the chain as it receives blocks from the network. Time is divided into slots of 30 seconds, called _epochs_. In each epoch, the protocol elects a set of network participants (i.e., storage providers) to become block proposers. Each proposer can construct a new block and broadcast it to the network. On reception, each participant appends the block to its local view of the blockchain. Each tipset has a _weight_ corresponding to the total number of blocks in the path between the genesis and the tipset (the actual weight function is slightly more complex in reality, but this approximation is sufficient for this document). An example blockchain data structure is shown below, indicating the weight of each tipset in parentheses. -![](../resources/fip-xxxx/chain.png) +![](../resources/fip-0086/chain.png) Two or more tipsets of the same epoch with different parent tipsets (like tipsets $C$ and $C'$ above) form a _fork_ in the chain. Forks are resolved using a _fork choice rule_, a deterministic algorithm that, given a blockchain data structure, returns the heaviest tipset, called the _head_. We refer to the path from genesis to the head as the _canonical chain_. Participants may have different views of the blockchain, resulting in other canonical chains. For example, if a participant $p_1$ is not (yet) aware of tipset $D$, it would consider $C$ the heaviest tipset with the canonical chain $[G A B C]$. Another participant $p_2$ aware of tipset $D$ will consider $[G A C' D]$ to be the canonical chain. Once $p_1$ becomes aware of tipset $D$, it will update its canonical chain to $[G A C' D]$ - this is called _reorganization_. We say a tipset is _finalized_ when a reorganization involving that tipset is impossible, i.e., when a different path that does not contain the tipset cannot become the canonical chain. @@ -58,7 +58,7 @@ In short, each participant $p$ in the Filecoin network (i.e., a storage provider - **EC:** Participant $p$ updates its local EC chain and commits not to reorganize the finalized tipset $t_i$, i.e., the tipset must stay in $p$'s EC canonical chain for good. Apart from this change, EC continues operating as it currently does. In particular, EC still does a 900-epoch lookback for its power table (which can therefore differ from the one used by F3) and continues operating “normally” if F3 assumptions are violated and F3 halts, with the combined EC/F3 protocol favoring availability over consistency (in CAP theorem parlance). - **F3 synchronization:** Participants disseminate information about finalized tipset $t_i$ and its proof $PoF_i$ to all other participants, light clients, and smart contracts. The main goal of F3 synchronization is to allow an external party (or a lagging F3 participant) to fetch a sequence of messages that prove the finality of some recent final tipset. The sequence demonstrates a chain of eligible participants deciding on a final tipset and, thus, the eligible power table for the next round. Verifying the finality of a tipset from genesis does not require validating the EC chain. -![](../resources/fip-xxxx/flow.png) +![](../resources/fip-0086/flow.png) ### F3 Adversarial Model @@ -194,7 +194,7 @@ This redefinition of the heaviest chain is consistent with the abstract notion o We illustrate the updated rule in the following figure, where blocks in blue are finalized blocks, and all blocks are assumed to be proposed by a proposer holding only one EC ticket (the weight of a chain is the number of blocks): -![](../resources/fip-xxxx/fork.png) +![](../resources/fip-0086/fork.png) The current EC fork-choice rule would select the tipset $\lbrace D_0, D_1\rbrace$ as the head of the heaviest chain. However, the heaviest finalized tipset is $\lbrace C_3\rbrace$, which is not an ancestor of $\lbrace D_0, D_1\rbrace$. Therefore, the new fork choice rule selects $\lbrace D_3\rbrace$ as the head of the heaviest chain. The reason why $D_4$ is not selected is that its parent tipset does not exactly match the finalized tipset $\lbrace C_3\rbrace$, but a superset of it, i.e. $\lbrace C_3, C_4\rbrace$. @@ -741,7 +741,7 @@ We refer to the stand-alone implementation in a simulated environment in the [go - [x] Complete benchmarking around message complexity and computational/networking requirements. - [x] Decide between implicit and explicit evidence, taking into account benchmark results. -- [ ] Finalize and incorporate the WIP [finality exchange protocol](https://docs.google.com/document/d/10i9tFremOSrZou9oO5A5wvu1uOy1lvFKbv8IsvoglR0/edit#heading=h.g8nngox3auow). +- [ ] Finalize and incorporate the WIP finality exchange protocol. - [ ] Update and move proofs of correctness and other supplemental documentation into `resources` diff --git a/resources/fip-xxxx/chain.png b/resources/fip-0086/chain.png similarity index 100% rename from resources/fip-xxxx/chain.png rename to resources/fip-0086/chain.png diff --git a/resources/fip-xxxx/flow.png b/resources/fip-0086/flow.png similarity index 100% rename from resources/fip-xxxx/flow.png rename to resources/fip-0086/flow.png diff --git a/resources/fip-xxxx/fork.png b/resources/fip-0086/fork.png similarity index 100% rename from resources/fip-xxxx/fork.png rename to resources/fip-0086/fork.png From cdc20ca4ef85447ece8550097cb11f1956025a88 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:57:12 +0100 Subject: [PATCH 31/33] Update authors --- FIPS/fip-0086.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-0086.md b/FIPS/fip-0086.md index 940452b7..8209c6cb 100644 --- a/FIPS/fip-0086.md +++ b/FIPS/fip-0086.md @@ -1,7 +1,7 @@ --- fip: "0086" title: Fast Finality in Filecoin (F3) -author: Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares) and Marko Vukolic (@vukolic) +author: Steven Allen (@stebalien), Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares), Jakub Sztandera (@Kubuxu), and Marko Vukolic (@vukolic) discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 status: Draft type: Technical From ab0ea99ec026e48f6bcbb0363f6ef64b7051e2c2 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:59:29 +0100 Subject: [PATCH 32/33] Update authors --- FIPS/fip-0086.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FIPS/fip-0086.md b/FIPS/fip-0086.md index 8209c6cb..c97a0129 100644 --- a/FIPS/fip-0086.md +++ b/FIPS/fip-0086.md @@ -1,7 +1,7 @@ --- fip: "0086" title: Fast Finality in Filecoin (F3) -author: Steven Allen (@stebalien), Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge Soares (@jsoares), Jakub Sztandera (@Kubuxu), and Marko Vukolic (@vukolic) +author: Steven Allen (@stebalien), Jie Hou (@mb1896), Henrique Moniz (@hmoniz), Alex North (@anorth), Matej Pavlovic (@matejpavlovic), Aayush Rajasekaran (@arajasek), Alejandro Ranchal-Pedrosa (@ranchalp), Jorge M. Soares (@jsoares), Jakub Sztandera (@Kubuxu), and Marko Vukolic (@vukolic) discussions-to: https://github.com/filecoin-project/FIPs/discussions/809 status: Draft type: Technical From eff08d7686c912a38b955362332d514d1fa7c965 Mon Sep 17 00:00:00 2001 From: Jorge Soares <547492+jsoares@users.noreply.github.com> Date: Tue, 6 Feb 2024 23:41:07 +0100 Subject: [PATCH 33/33] Add to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index db16e9a0..856837ec 100644 --- a/README.md +++ b/README.md @@ -123,3 +123,4 @@ This improvement protocol helps achieve that objective for all members of the Fi |[0083](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0083.md) | Add built-in Actor events in the Verified Registry, Miner and Market Actors | FIP | Aarsh (@aarshkshah1992)| Last call | |[0084](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0084.md) | Remove Storage Miner Actor Method `ProveCommitSectors` | FIP | Jennifer Wang (@jennijuju)| Last Call | |[0085](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0085.md) | Convert f090 Mining Reserve actor to a keyless account actor | FIP | Jennifer Wang (@jennijuju), Jon Victor (@jnthnvctr)| Draft | +|[0086](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0086.md) | Fast Finality in Filecoin (F3) | FIP | @stebalien, @mb1896, @hmoniz, @anorth, @matejpavlovic, @arajasek, @ranchalp, @jsoares, @Kubuxu, @vukolic | Draft | \ No newline at end of file