github.com/aakash4dev/cometbft@v0.38.2/spec/light-client/attacks/LCVerificationApi_003_draft.tla (about)

     1  -------------------- MODULE LCVerificationApi_003_draft --------------------------
     2  (**
     3   * The common interface of the light client verification and detection.
     4   *) 
     5  EXTENDS Integers, FiniteSets
     6  
     7  \* the parameters of Light Client
     8  CONSTANTS
     9    TRUSTING_PERIOD,
    10      (* the period within which the validators are trusted *)
    11    CLOCK_DRIFT,
    12      (* the assumed precision of the clock *)
    13    REAL_CLOCK_DRIFT,
    14      (* the actual clock drift, which under normal circumstances should not
    15         be larger than CLOCK_DRIFT (otherwise, there will be a bug) *)
    16    FAULTY_RATIO
    17      (* a pair <<a, b>> that limits that ratio of faulty validator in the blockchain
    18         from above (exclusive). Cosmos security model prescribes 1 / 3. *)
    19  
    20  VARIABLES  
    21    localClock (* current time as measured by the light client *)
    22  
    23  (* the header is still within the trusting period *)
    24  InTrustingPeriodLocal(header) ==
    25      \* note that the assumption about the drift reduces the period of trust
    26      localClock < header.time + TRUSTING_PERIOD - CLOCK_DRIFT
    27  
    28  (* the header is still within the trusting period, even if the clock can go backwards *)
    29  InTrustingPeriodLocalSurely(header) ==
    30      \* note that the assumption about the drift reduces the period of trust
    31      localClock < header.time + TRUSTING_PERIOD - 2 * CLOCK_DRIFT
    32  
    33  (* ensure that the local clock does not drift far away from the global clock *)
    34  IsLocalClockWithinDrift(local, global) ==
    35      /\ global - REAL_CLOCK_DRIFT <= local
    36      /\ local <= global + REAL_CLOCK_DRIFT
    37  
    38  (**
    39    * Check that the commits in an untrusted block form 1/3 of the next validators
    40    * in a trusted header.
    41   *)
    42  SignedByOneThirdOfTrusted(trusted, untrusted) ==
    43    LET TP == Cardinality(trusted.header.NextVS)
    44        SP == Cardinality(untrusted.Commits \intersect trusted.header.NextVS)
    45    IN
    46    3 * SP > TP     
    47  
    48  (**
    49   The first part of the precondition of ValidAndVerified, which does not take
    50   the current time into account.
    51   
    52   [LCV-FUNC-VALID.1::TLA-PRE-UNTIMED.1]
    53   *)
    54  ValidAndVerifiedPreUntimed(trusted, untrusted) ==
    55    LET thdr == trusted.header
    56        uhdr == untrusted.header
    57    IN
    58    /\ thdr.height < uhdr.height
    59       \* the trusted block has been created earlier
    60    /\ thdr.time < uhdr.time
    61    /\ untrusted.Commits \subseteq uhdr.VS
    62    /\ LET TP == Cardinality(uhdr.VS)
    63           SP == Cardinality(untrusted.Commits)
    64       IN
    65       3 * SP > 2 * TP     
    66    /\ thdr.height + 1 = uhdr.height => thdr.NextVS = uhdr.VS
    67    (* As we do not have explicit hashes we ignore these three checks of the English spec:
    68     
    69       1. "trusted.Commit is a commit is for the header trusted.Header,
    70        i.e. it contains the correct hash of the header".
    71       2. untrusted.Validators = hash(untrusted.Header.Validators)
    72       3. untrusted.NextValidators = hash(untrusted.Header.NextValidators)
    73     *)
    74  
    75  (**
    76   Check the precondition of ValidAndVerified, including the time checks.
    77   
    78   [LCV-FUNC-VALID.1::TLA-PRE.1]
    79   *)
    80  ValidAndVerifiedPre(trusted, untrusted, checkFuture) ==
    81    LET thdr == trusted.header
    82        uhdr == untrusted.header
    83    IN
    84    /\ InTrustingPeriodLocal(thdr)
    85       \* The untrusted block is not from the future (modulo clock drift).
    86       \* Do the check, if it is required.
    87    /\ checkFuture => uhdr.time < localClock + CLOCK_DRIFT
    88    /\ ValidAndVerifiedPreUntimed(trusted, untrusted)
    89  
    90  
    91  (**
    92   Check, whether an untrusted block is valid and verifiable w.r.t. a trusted header.
    93   This test does take current time into account, but only looks at the block structure.
    94   
    95   [LCV-FUNC-VALID.1::TLA-UNTIMED.1]
    96   *)   
    97  ValidAndVerifiedUntimed(trusted, untrusted) ==
    98      IF ~ValidAndVerifiedPreUntimed(trusted, untrusted)
    99      THEN "INVALID"
   100      ELSE IF untrusted.header.height = trusted.header.height + 1
   101               \/ SignedByOneThirdOfTrusted(trusted, untrusted)
   102           THEN "SUCCESS"
   103           ELSE "NOT_ENOUGH_TRUST"
   104  
   105  (**
   106   Check, whether an untrusted block is valid and verifiable w.r.t. a trusted header.
   107   
   108   [LCV-FUNC-VALID.1::TLA.1]
   109   *)   
   110  ValidAndVerified(trusted, untrusted, checkFuture) ==
   111      IF ~ValidAndVerifiedPre(trusted, untrusted, checkFuture)
   112      THEN "INVALID"
   113      ELSE IF ~InTrustingPeriodLocal(untrusted.header)
   114      (* We leave the following test for the documentation purposes.
   115         The implementation should do this test, as signature verification may be slow.
   116         In the TLA+ specification, ValidAndVerified happens in no time.
   117       *) 
   118      THEN "FAILED_TRUSTING_PERIOD" 
   119      ELSE IF untrusted.header.height = trusted.header.height + 1
   120               \/ SignedByOneThirdOfTrusted(trusted, untrusted)
   121           THEN "SUCCESS"
   122           ELSE "NOT_ENOUGH_TRUST"
   123  
   124  
   125  (**
   126    The invariant of the light store that is not related to the blockchain
   127   *)
   128  LightStoreInv(fetchedLightBlocks, lightBlockStatus) ==
   129      \A lh, rh \in DOMAIN fetchedLightBlocks:
   130              \* for every pair of stored headers that have been verified
   131          \/ lh >= rh
   132          \/ lightBlockStatus[lh] /= "StateVerified"
   133          \/ lightBlockStatus[rh] /= "StateVerified"
   134             \* either there is a header between them
   135          \/ \E mh \in DOMAIN fetchedLightBlocks:
   136              lh < mh /\ mh < rh /\ lightBlockStatus[mh] = "StateVerified"
   137             \* or the left header is outside the trusting period, so no guarantees
   138          \/ LET lhdr == fetchedLightBlocks[lh]
   139                 rhdr == fetchedLightBlocks[rh]
   140             IN
   141             \* we can verify the right one using the left one
   142             "SUCCESS" = ValidAndVerifiedUntimed(lhdr, rhdr)
   143  
   144  (**
   145    Correctness states that all the obtained headers are exactly like in the blockchain.
   146   
   147    It is always the case that every verified header in LightStore was generated by
   148    an instance of Tendermint consensus.
   149    
   150    [LCV-DIST-SAFE.1::CORRECTNESS-INV.1]
   151   *)  
   152  CorrectnessInv(blockchain, fetchedLightBlocks, lightBlockStatus) ==
   153      \A h \in DOMAIN fetchedLightBlocks:
   154          lightBlockStatus[h] = "StateVerified" =>
   155              fetchedLightBlocks[h].header = blockchain[h]
   156  
   157  (**
   158   * When the light client terminates, there are no failed blocks.
   159   * (Otherwise, someone lied to us.) 
   160   *)            
   161  NoFailedBlocksOnSuccessInv(fetchedLightBlocks, lightBlockStatus) ==
   162       \A h \in DOMAIN fetchedLightBlocks:
   163          lightBlockStatus[h] /= "StateFailed"            
   164  
   165  (**
   166   The expected post-condition of VerifyToTarget.
   167   *)
   168  VerifyToTargetPost(blockchain, isPeerCorrect,
   169                     fetchedLightBlocks, lightBlockStatus,
   170                     trustedHeight, targetHeight, finalState) ==
   171    LET trustedHeader == fetchedLightBlocks[trustedHeight].header IN
   172      \* The light client is not lying us on the trusted block.
   173      \* It is straightforward to detect.
   174      /\ lightBlockStatus[trustedHeight] = "StateVerified"
   175      /\ trustedHeight \in DOMAIN fetchedLightBlocks
   176      /\ trustedHeader = blockchain[trustedHeight]
   177      \* the invariants we have found in the light client verification
   178      \* there is a problem with trusting period
   179      /\ isPeerCorrect
   180          => CorrectnessInv(blockchain, fetchedLightBlocks, lightBlockStatus)
   181      \* a correct peer should fail the light client,
   182      \* if the trusted block is in the trusting period
   183      /\ isPeerCorrect /\ InTrustingPeriodLocalSurely(trustedHeader)
   184          => finalState = "finishedSuccess"
   185      /\ finalState = "finishedSuccess" =>
   186          /\ lightBlockStatus[targetHeight] = "StateVerified"
   187          /\ targetHeight \in DOMAIN fetchedLightBlocks
   188          /\ NoFailedBlocksOnSuccessInv(fetchedLightBlocks, lightBlockStatus)
   189      /\ LightStoreInv(fetchedLightBlocks, lightBlockStatus)
   190  
   191  
   192  ==================================================================================