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