github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/slashing/spec/04_begin_block.md (about)

     1  <!--
     2  order: 4
     3  -->
     4  
     5  # BeginBlock
     6  
     7  ## Liveness Tracking
     8  
     9  At the beginning of each block, we update the `ValidatorSigningInfo` for each
    10  validator and check if they've crossed below the liveness threshold over a
    11  sliding window. This sliding window is defined by `SignedBlocksWindow` and the
    12  index in this window is determined by `IndexOffset` found in the validator's
    13  `ValidatorSigningInfo`. For each block processed, the `IndexOffset` is incremented
    14  regardless if the validator signed or not. Once the index is determined, the
    15  `MissedBlocksBitArray` and `MissedBlocksCounter` are updated accordingly.
    16  
    17  Finally, in order to determine if a validator crosses below the liveness threshold,
    18  we fetch the maximum number of blocks missed, `maxMissed`, which is
    19  `SignedBlocksWindow - (MinSignedPerWindow * SignedBlocksWindow)` and the minimum
    20  height at which we can determine liveness, `minHeight`. If the current block is
    21  greater than `minHeight` and the validator's `MissedBlocksCounter` is greater than
    22  `maxMissed`, they will be slashed by `SlashFractionDowntime`, will be jailed
    23  for `DowntimeJailDuration`, and have the following values reset:
    24  `MissedBlocksBitArray`, `MissedBlocksCounter`, and `IndexOffset`.
    25  
    26  __Note__: Liveness slashes do **NOT** lead to a tombstombing.
    27  
    28  ```go
    29  height := block.Height
    30  
    31  for vote in block.LastCommitInfo.Votes {
    32    signInfo := GetValidatorSigningInfo(vote.Validator.Address)
    33  
    34    // This is a relative index, so we counts blocks the validator SHOULD have
    35    // signed. We use the 0-value default signing info if not present, except for
    36    // start height.
    37    index := signInfo.IndexOffset % SignedBlocksWindow()
    38    signInfo.IndexOffset++
    39  
    40    // Update MissedBlocksBitArray and MissedBlocksCounter. The MissedBlocksCounter
    41    // just tracks the sum of MissedBlocksBitArray. That way we avoid needing to
    42    // read/write the whole array each time.
    43    missedPrevious := GetValidatorMissedBlockBitArray(vote.Validator.Address, index)
    44    missed := !signed
    45  
    46    switch {
    47    case !missedPrevious && missed:
    48      // array index has changed from not missed to missed, increment counter
    49      SetValidatorMissedBlockBitArray(vote.Validator.Address, index, true)
    50      signInfo.MissedBlocksCounter++
    51  
    52    case missedPrevious && !missed:
    53      // array index has changed from missed to not missed, decrement counter
    54      SetValidatorMissedBlockBitArray(vote.Validator.Address, index, false)
    55      signInfo.MissedBlocksCounter--
    56  
    57    default:
    58      // array index at this index has not changed; no need to update counter
    59    }
    60  
    61    if missed {
    62      // emit events...
    63    }
    64  
    65    minHeight := signInfo.StartHeight + SignedBlocksWindow()
    66    maxMissed := SignedBlocksWindow() - MinSignedPerWindow()
    67  
    68    // If we are past the minimum height and the validator has missed too many
    69    // jail and slash them.
    70    if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {
    71      validator := ValidatorByConsAddr(vote.Validator.Address)
    72  
    73      // emit events...
    74  
    75      // We need to retrieve the stake distribution which signed the block, so we
    76      // subtract ValidatorUpdateDelay from the block height, and subtract an
    77      // additional 1 since this is the LastCommit.
    78      //
    79      // Note, that this CAN result in a negative "distributionHeight" up to
    80      // -ValidatorUpdateDelay-1, i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block.
    81      // That's fine since this is just used to filter unbonding delegations & redelegations.
    82      distributionHeight := height - sdk.ValidatorUpdateDelay - 1
    83  
    84      Slash(vote.Validator.Address, distributionHeight, vote.Validator.Power, SlashFractionDowntime())
    85      Jail(vote.Validator.Address)
    86  
    87      signInfo.JailedUntil = block.Time.Add(DowntimeJailDuration())
    88  
    89      // We need to reset the counter & array so that the validator won't be
    90      // immediately slashed for downtime upon rebonding.
    91      signInfo.MissedBlocksCounter = 0
    92      signInfo.IndexOffset = 0
    93      ClearValidatorMissedBlockBitArray(vote.Validator.Address)
    94    }
    95  
    96    SetValidatorSigningInfo(vote.Validator.Address, signInfo)
    97  }
    98  ```