|
|
- ----------------------- MODULE Isolation_001_draft ----------------------------
- (**
- * The specification of the attackers isolation at full node,
- * when it has received an evidence from the light client.
- * We check that the isolation spec produces a set of validators
- * that have more than 1/3 of the voting power.
- *
- * It follows the English specification:
- *
- * https://github.com/tendermint/spec/blob/master/rust-spec/lightclient/attacks/isolate-attackers_001_draft.md
- *
- * The assumptions made in this specification:
- *
- * - the voting power of every validator is 1
- * (add more validators, if you need more validators)
- *
- * - Tendermint security model is violated
- * (there are Byzantine validators who signed a conflicting block)
- *
- * Igor Konnov, Zarko Milosevic, Josef Widder, Informal Systems, 2020
- *)
-
-
- EXTENDS Integers, FiniteSets, Apalache
-
- \* algorithm parameters
- CONSTANTS
- AllNodes,
- (* a set of all nodes that can act as validators (correct and faulty) *)
- COMMON_HEIGHT,
- (* an index of the block header that two peers agree upon *)
- CONFLICT_HEIGHT,
- (* an index of the block header that two peers disagree upon *)
- TRUSTING_PERIOD,
- (* the period within which the validators are trusted *)
- FAULTY_RATIO
- (* a pair <<a, b>> that limits that ratio of faulty validator in the blockchain
- from above (exclusive). Tendermint security model prescribes 1 / 3. *)
-
- VARIABLES
- blockchain, (* the chain at the full node *)
- refClock, (* the reference clock at the full node *)
- Faulty, (* the set of faulty validators *)
- conflictingBlock, (* an evidence that two peers reported conflicting blocks *)
- state, (* the state of the attack isolation machine at the full node *)
- attackers (* the set of the identified attackers *)
-
- vars == <<blockchain, refClock, Faulty, conflictingBlock, state>>
-
- \* instantiate the chain at the full node
- ULTIMATE_HEIGHT == CONFLICT_HEIGHT + 1
- BC == INSTANCE Blockchain_003_draft
-
- \* use the light client API
- TRUSTING_HEIGHT == COMMON_HEIGHT
- TARGET_HEIGHT == CONFLICT_HEIGHT
-
- LC == INSTANCE LCVerificationApi_003_draft
- WITH localClock <- refClock, REAL_CLOCK_DRIFT <- 0, CLOCK_DRIFT <- 0
-
- \* old-style type annotations in apalache
- a <: b == a
-
- \* [LCAI-NONVALID-OUTPUT.1::TLA.1]
- ViolatesValidity(header1, header2) ==
- \/ header1.VS /= header2.VS
- \/ header1.NextVS /= header2.NextVS
- \/ header1.height /= header2.height
- \/ header1.time /= header2.time
- (* The English specification also checks the fields that we do not have
- at this level of abstraction:
- - header1.ConsensusHash != header2.ConsensusHash or
- - header1.AppHash != header2.AppHash or
- - header1.LastResultsHash header2 != ev.LastResultsHash
- *)
-
- Init ==
- /\ state := "init"
- \* Pick an arbitrary blockchain from 1 to COMMON_HEIGHT + 1.
- /\ BC!InitToHeight(FAULTY_RATIO) \* initializes blockchain, Faulty, and refClock
- /\ attackers := {} <: {STRING} \* attackers are unknown
- \* Receive an arbitrary evidence.
- \* Instantiate the light block fields one by one,
- \* to avoid combinatorial explosion of records.
- /\ \E time \in Int:
- \E VS, NextVS, lastCommit, Commits \in SUBSET AllNodes:
- LET conflicting ==
- [ Commits |-> Commits,
- header |->
- [height |-> CONFLICT_HEIGHT,
- time |-> time,
- VS |-> VS,
- NextVS |-> NextVS,
- lastCommit |-> lastCommit] ]
- IN
- LET refBlock == [ header |-> blockchain[COMMON_HEIGHT],
- Commits |-> blockchain[COMMON_HEIGHT + 1].lastCommit ]
- IN
- /\ "SUCCESS" = LC!ValidAndVerifiedUntimed(refBlock, conflicting)
- \* More than third of next validators in the common reference block
- \* is faulty. That is a precondition for a fork.
- /\ 3 * Cardinality(Faulty \intersect refBlock.header.NextVS)
- > Cardinality(refBlock.header.NextVS)
- \* correct validators cannot sign an invalid block
- /\ ViolatesValidity(conflicting.header, refBlock.header)
- => conflicting.Commits \subseteq Faulty
- /\ conflictingBlock := conflicting
-
-
- \* This is a specification of isolateMisbehavingProcesses.
- \*
- \* [LCAI-FUNC-MAIN.1::TLA.1]
- Next ==
- /\ state = "init"
- \* Extract the rounds from the reference block and the conflicting block.
- \* In this specification, we just pick rounds non-deterministically.
- \* The English specification calls RoundOf on the blocks.
- /\ \E referenceRound, evidenceRound \in Int:
- /\ referenceRound >= 0 /\ evidenceRound >= 0
- /\ LET reference == blockchain[CONFLICT_HEIGHT]
- referenceCommit == blockchain[CONFLICT_HEIGHT + 1].lastCommit
- evidenceHeader == conflictingBlock.header
- evidenceCommit == conflictingBlock.Commits
- IN
- IF ViolatesValidity(reference, evidenceHeader)
- THEN /\ attackers' := blockchain[COMMON_HEIGHT].NextVS \intersect evidenceCommit
- /\ state' := "Lunatic"
- ELSE IF referenceRound = evidenceRound
- THEN /\ attackers' := referenceCommit \intersect evidenceCommit
- /\ state' := "Equivocation"
- ELSE
- \* This property is shown in property
- \* Accountability of TendermintAcc3.tla
- /\ state' := "Amnesia"
- /\ \E Attackers \in SUBSET (Faulty \intersect reference.VS):
- /\ 3 * Cardinality(Attackers) > Cardinality(reference.VS)
- /\ attackers' := Attackers
- /\ blockchain' := blockchain
- /\ refClock' := refClock
- /\ Faulty' := Faulty
- /\ conflictingBlock' := conflictingBlock
-
- (********************************** INVARIANTS *******************************)
-
- \* This invariant ensure that the attackers have
- \* more than 1/3 of the voting power
- \*
- \* [LCAI-INV-Output.1::TLA-DETECTION-COMPLETENESS.1]
- DetectionCompleteness ==
- state /= "init" =>
- 3 * Cardinality(attackers) > Cardinality(blockchain[CONFLICT_HEIGHT].VS)
-
- \* This invariant ensures that only the faulty validators are detected
- \*
- \* [LCAI-INV-Output.1::TLA-DETECTION-ACCURACY.1]
- DetectionAccuracy ==
- attackers \subseteq Faulty
-
- ==============================================================================
|