github.com/vipernet-xyz/tm@v0.34.24/spec/light-client/detection/draft-functions.md (about)

     1  # Draft of Functions for Fork detection and Proof of Fork Submisstion
     2  
     3  This document collects drafts of function for generating and
     4  submitting proof of fork in the IBC context
     5  
     6  - [IBC](#on---chain-ibc-component)
     7  
     8  - [Relayer](#relayer)
     9  
    10  ## On-chain IBC Component
    11  
    12  > The following is a suggestions to change the function defined in ICS 007
    13  
    14  #### [TAG-IBC-MISBEHAVIOR.1]
    15  
    16  ```go
    17  func checkMisbehaviourAndUpdateState(cs: ClientState, PoF: LightNodeProofOfFork)
    18  ```
    19  
    20  **TODO:** finish conditions
    21  
    22  - Implementation remark
    23  - Expected precondition
    24      - PoF.TrustedBlock.Header is equal to lightBlock on store with
    25        same height
    26      - both traces end with header of same height
    27      - headers are different
    28      - both traces are supported by PoF.TrustedBlock (`supports`
    29     defined in [TMBC-FUNC]), that is, for `t = currentTimestamp()` (see
    30     ICS 024)
    31          - supports(PoF.TrustedBlock, PoF.PrimaryTrace[1], t)
    32          - supports(PoF.PrimaryTrace[i], PoF.PrimaryTrace[i+1], t) for
    33       *0 < i < length(PoF.PrimaryTrace)*
    34          - supports(PoF.TrustedBlock,  PoF.SecondaryTrace[1], t)
    35          - supports(PoF.SecondaryTrace[i], PoF.SecondaryTrace[i+1], t) for
    36       *0 < i < length(PoF.SecondaryTrace)*  
    37  - Expected postcondition
    38      - set cs.FrozenHeight to min(cs.FrozenHeight, PoF.TrustedBlock.Header.Height)
    39  - Error condition
    40      - none
    41  
    42  ----
    43  
    44  > The following is a suggestions to add functionality to ICS 002 and 007.
    45  > I suppose the above is the most efficient way to get the required
    46  > information. Another option is to subscribe to "header install"
    47  > events via CosmosSDK
    48  
    49  #### [TAG-IBC-HEIGHTS.1]
    50  
    51  ```go
    52  func QueryHeightsRange(id, from, to) ([]Height)
    53  ```
    54  
    55  - Expected postcondition
    56      - returns all heights *h*, with *from <= h <= to* for which the
    57        IBC component has a consensus state.
    58  
    59  ----
    60  
    61  > This function can be used if the relayer has no information about
    62  > the IBC component. This allows late-joining relayers to also
    63  > participate in fork dection and the generation in proof of
    64  > fork. Alternatively, we may also postulate that relayers are not
    65  > responsible to detect forks for heights before they started (and
    66  > subscribed to the transactions reporting fresh headers being
    67  > installed at the IBC component).
    68  
    69  ## Relayer
    70  
    71  ### Auxiliary Functions to be implemented in the Light Client
    72  
    73  #### [LCV-LS-FUNC-GET-PREV.1]
    74  
    75  ```go
    76  func (ls LightStore) GetPreviousVerified(height Height) (LightBlock, bool)
    77  ```
    78  
    79  - Expected postcondition
    80      - returns a verified LightBlock, whose height is maximal among all
    81        verified lightblocks with height smaller than `height`
    82  
    83  ----
    84  
    85  ### Relayer Submitting Proof of Fork to the IBC Component
    86  
    87  There are two ways the relayer can detect a fork
    88  
    89  - by the fork detector of one of its lightclients
    90  - be checking the consensus state of the IBC component
    91  
    92  The following function ignores how the proof of fork was generated.
    93  It takes a proof of fork as input and computes a proof of fork that
    94       will be accepted by the IBC component.
    95  The problem addressed here is that both, the relayer's light client
    96       and the IBC component have incomplete light stores, that might
    97       not have all light blocks in common.
    98  Hence the relayer has to figure out what the IBC component knows
    99       (intuitively, a meeting point between the two lightstores
   100       computed in `commonRoot`)  and compute a proof of fork
   101       (`extendPoF`) that the IBC component will accept based on its
   102       knowledge.
   103  
   104  The auxiliary functions `commonRoot` and `extendPoF` are
   105  defined below.
   106  
   107  #### [TAG-SUBMIT-POF-IBC.1]
   108  
   109  ```go
   110  func SubmitIBCProofOfFork(
   111    lightStore LightStore,
   112    PoF: LightNodeProofOfFork,
   113    ibc IBCComponent) (Error) {
   114      if ibc.queryChainConsensusState(PoF.TrustedBlock.Height) = PoF.TrustedBlock {
   115    // IBC component has root of PoF on store, we can just submit
   116          ibc.submitMisbehaviourToClient(ibc.id,PoF)
   117    return Success
   118       // note sure about the id parameter
   119      }
   120      else {
   121          // the ibc component does not have the TrustedBlock and might
   122    // even be on yet a different branch. We have to compute a PoF
   123    // that the ibc component can verifiy based on its current
   124          // knowledge
   125    
   126          ibcLightBlock, lblock, _, result := commonRoot(lightStore, ibc, PoF.TrustedBlock)
   127  
   128       if result = Success {
   129     newPoF = extendPoF(ibcLightBlock, lblock, lightStore, PoF)
   130        ibc.submitMisbehaviourToClient(ibc.id, newPoF)
   131        return Success
   132       }
   133    else{
   134     return CouldNotGeneratePoF
   135       }
   136      }
   137  }
   138  ```
   139  
   140  **TODO:** finish conditions
   141  
   142  - Implementation remark
   143  - Expected precondition
   144  - Expected postcondition
   145  - Error condition
   146      - none
   147  
   148  ----
   149  
   150  ### Auxiliary Functions at the Relayer
   151  
   152  > If the relayer detects a fork, it has to compute a proof of fork that
   153  > will convince the IBC component. That is it has to compare the
   154  > relayer's local lightstore against the lightstore of the IBC
   155  > component, and find common ancestor lightblocks.
   156  
   157  #### [TAG-COMMON-ROOT.1]
   158  
   159  ```go
   160  func commonRoot(lightStore LightStore, ibc IBCComponent, lblock
   161  LightBlock) (LightBlock, LightBlock, LightStore, Result) {
   162  
   163      auxLS.Init
   164  
   165         // first we ask for the heights the ibc component is aware of
   166    ibcHeights = ibc.QueryHeightsRange(
   167                       ibc.id,
   168                       lightStore.LowestVerified().Height,
   169                       lblock.Height - 1);
   170    // this function does not exist yet. Alternatively, we may
   171    // request all transactions that installed headers via CosmosSDK
   172    
   173  
   174          for {
   175              h, result = max(ibcHeights)
   176     if result = Empty {
   177         return (_, _, _, NoRoot)
   178        }
   179        ibcLightBlock = ibc.queryChainConsensusState(h)
   180     auxLS.Update(ibcLightBlock, StateVerified);
   181        connector, result := Connector(lightStore, ibcLightBlock, lblock.Header.Height)
   182        if result = success {
   183         return (ibcLightBlock, connector, auxLS, Success)
   184     }
   185     else{
   186         ibcHeights.remove(h)
   187        }
   188    }
   189  }
   190  ```
   191  
   192  - Expected postcondition
   193      - returns
   194          - a lightBlock b1 from the IBC component, and
   195          - a lightBlock b2
   196              from the local lightStore with height less than
   197     lblock.Header.Hight, s.t. b1 supports b2, and
   198          - a lightstore with the blocks downloaded from
   199            the ibc component
   200  
   201  ----
   202  
   203  #### [TAG-LS-FUNC-CONNECT.1]
   204  
   205  ```go
   206  func Connector (lightStore LightStore, lb LightBlock, h Height) (LightBlock, bool)
   207  ```
   208  
   209  - Expected postcondition
   210      - returns a verified LightBlock from lightStore with height less
   211        than *h* that can be
   212        verified by lb in one step.
   213  
   214  **TODO:** for the above to work we need an invariant that all verified
   215  lightblocks form a chain of trust. Otherwise, we need a lightblock
   216  that has a chain of trust to height.
   217  
   218  > Once the common root is found, a proof of fork that will be accepted
   219  > by the IBC component needs to be generated. This is done in the
   220  > following function.
   221  
   222  #### [TAG-EXTEND-POF.1]
   223  
   224  ```go
   225  func extendPoF (root LightBlock,
   226                  connector LightBlock,
   227      lightStore LightStore,
   228      Pof LightNodeProofofFork) (LightNodeProofofFork}
   229  ```
   230  
   231  - Implementation remark
   232      - PoF is not sufficient to convince an IBC component, so we extend
   233        the proof of fork farther in the past
   234  - Expected postcondition
   235      - returns a newPOF:
   236          - newPoF.TrustedBlock = root
   237          - let prefix =
   238         connector +
   239         lightStore.Subtrace(connector.Header.Height, PoF.TrustedBlock.Header.Height-1) +
   240         PoF.TrustedBlock  
   241              - newPoF.PrimaryTrace = prefix + PoF.PrimaryTrace
   242              - newPoF.SecondaryTrace = prefix + PoF.SecondaryTrace
   243  
   244  ### Detection a fork at the IBC component
   245  
   246  The following functions is assumed to be called regularly to check
   247  that latest consensus state of the IBC component. Alternatively, this
   248  logic can be executed whenever the relayer is informed (via an event)
   249  that a new header has been installed.
   250  
   251  #### [TAG-HANDLER-DETECT-FORK.1]
   252  
   253  ```go
   254  func DetectIBCFork(ibc IBCComponent, lightStore LightStore) (LightNodeProofOfFork, Error) {
   255      cs = ibc.queryClientState(ibc);
   256   lb, found := lightStore.Get(cs.Header.Height)
   257      if !found {
   258   **TODO:** need verify to target
   259          lb, result = LightClient.Main(primary, lightStore, cs.Header.Height)
   260    // [LCV-FUNC-IBCMAIN.1]
   261    **TODO** decide what to do following the outcome of Issue #499
   262    
   263    // I guess here we have to get into the light client
   264  
   265      }
   266   if cs != lb {
   267       // IBC component disagrees with my primary.
   268    // I fetch the
   269       ibcLightBlock, lblock, ibcStore, result := commonRoot(lightStore, ibc, lb)
   270    pof = new LightNodeProofOfFork;
   271    pof.TrustedBlock := ibcLightBlock
   272    pof.PrimaryTrace := ibcStore + cs
   273    pof.SecondaryTrace :=  lightStore.Subtrace(lblock.Header.Height,
   274                                      lb.Header.Height);
   275          return(pof, Fork)
   276   }
   277   return(nil , NoFork)
   278  }
   279  ```
   280  
   281  **TODO:** finish conditions
   282  
   283  - Implementation remark
   284      - we ask the handler for the lastest check. Cross-check with the
   285        chain. In case they deviate we generate PoF.
   286      - we assume IBC component is correct. It has verified the
   287        consensus state
   288  - Expected precondition
   289  - Expected postcondition