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 ==================================================================================