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