github.com/Finschia/finschia-sdk@v0.48.1/x/evidence/spec/06_begin_block.md (about)

     1  <!--
     2  order: 6
     3  -->
     4  
     5  # BeginBlock
     6  
     7  ## Evidence Handling
     8  
     9  Tendermint blocks can include
    10  [Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly.
    11  
    12  ### Equivocation
    13  
    14  Currently, the SDK handles two types of evidence inside the ABCI `BeginBlock`:
    15  
    16  - `DuplicateVoteEvidence`,
    17  - `LightClientAttackEvidence`.
    18  
    19  The evidence module handles these two evidence types the same way. First, the SDK converts the Tendermint concrete evidence type to a SDK `Evidence` interface using `Equivocation` as the concrete type.
    20  
    21  ```proto
    22  // Equivocation implements the Evidence interface.
    23  message Equivocation {
    24    int64                     height            = 1;
    25    google.protobuf.Timestamp time              = 2;
    26    int64                     power             = 3;
    27    string                    consensus_address = 4;
    28  }
    29  ```
    30  
    31  For some `Equivocation` submitted in `block` to be valid, it must satisfy:
    32  
    33  `Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge`
    34  
    35  Where:
    36  
    37  - `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height`
    38  - `block.Timestamp` is the current block timestamp.
    39  
    40  If valid `Equivocation` evidence is included in a block, the validator's stake is
    41  reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module
    42  of what their stake was when the infraction occurred, rather than when the evidence was discovered.
    43  We want to "follow the stake", i.e., the stake that contributed to the infraction
    44  should be slashed, even if it has since been redelegated or started unbonding.
    45  
    46  In addition, the validator is permanently jailed and tombstoned to make it impossible for that
    47  validator to ever re-enter the validator set.
    48  
    49  The `Equivocation` evidence is handled as follows:
    50  
    51  ```go
    52  func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) {
    53  	logger := k.Logger(ctx)
    54  	consAddr := evidence.GetConsensusAddress()
    55  
    56  	if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil {
    57  		// Ignore evidence that cannot be handled.
    58  		//
    59  		// NOTE: We used to panic with:
    60  		// `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`,
    61  		// but this couples the expectations of the app to both Tendermint and
    62  		// the simulator.  Both are expected to provide the full range of
    63  		// allowable but none of the disallowed evidence types.  Instead of
    64  		// getting this coordination right, it is easier to relax the
    65  		// constraints and ignore evidence that cannot be handled.
    66  		return
    67  	}
    68  
    69  	// calculate the age of the evidence
    70  	infractionHeight := evidence.GetHeight()
    71  	infractionTime := evidence.GetTime()
    72  	ageDuration := ctx.BlockHeader().Time.Sub(infractionTime)
    73  	ageBlocks := ctx.BlockHeader().Height - infractionHeight
    74  
    75  	// Reject evidence if the double-sign is too old. Evidence is considered stale
    76  	// if the difference in time and number of blocks is greater than the allowed
    77  	// parameters defined.
    78  	cp := ctx.ConsensusParams()
    79  	if cp != nil && cp.Evidence != nil {
    80  		if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks {
    81  			logger.Info(
    82  				"ignored equivocation; evidence too old",
    83  				"validator", consAddr,
    84  				"infraction_height", infractionHeight,
    85  				"max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks,
    86  				"infraction_time", infractionTime,
    87  				"max_age_duration", cp.Evidence.MaxAgeDuration,
    88  			)
    89  			return
    90  		}
    91  	}
    92  
    93  	validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr)
    94  	if validator == nil || validator.IsUnbonded() {
    95  		// Defensive: Simulation doesn't take unbonding periods into account, and
    96  		// Tendermint might break this assumption at some point.
    97  		return
    98  	}
    99  
   100  	if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok {
   101  		panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr))
   102  	}
   103  
   104  	// ignore if the validator is already tombstoned
   105  	if k.slashingKeeper.IsTombstoned(ctx, consAddr) {
   106  		logger.Info(
   107  			"ignored equivocation; validator already tombstoned",
   108  			"validator", consAddr,
   109  			"infraction_height", infractionHeight,
   110  			"infraction_time", infractionTime,
   111  		)
   112  		return
   113  	}
   114  
   115  	logger.Info(
   116  		"confirmed equivocation",
   117  		"validator", consAddr,
   118  		"infraction_height", infractionHeight,
   119  		"infraction_time", infractionTime,
   120  	)
   121  
   122  	// We need to retrieve the stake distribution which signed the block, so we
   123  	// subtract ValidatorUpdateDelay from the evidence height.
   124  	// Note, that this *can* result in a negative "distributionHeight", up to
   125  	// -ValidatorUpdateDelay, i.e. at the end of the
   126  	// pre-genesis block (none) = at the beginning of the genesis block.
   127  	// That's fine since this is just used to filter unbonding delegations & redelegations.
   128  	distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay
   129  
   130  	// Slash validator. The `power` is the int64 power of the validator as provided
   131  	// to/by Tendermint. This value is validator.Tokens as sent to Tendermint via
   132  	// ABCI, and now received as evidence. The fraction is passed in to separately
   133  	// to slash unbonding and rebonding delegations.
   134  	k.slashingKeeper.Slash(
   135  		ctx,
   136  		consAddr,
   137  		k.slashingKeeper.SlashFractionDoubleSign(ctx),
   138  		evidence.GetValidatorPower(), distributionHeight,
   139  	)
   140  
   141  	// Jail the validator if not already jailed. This will begin unbonding the
   142  	// validator if not already unbonding (tombstoned).
   143  	if !validator.IsJailed() {
   144  		k.slashingKeeper.Jail(ctx, consAddr)
   145  	}
   146  
   147  	k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime)
   148  	k.slashingKeeper.Tombstone(ctx, consAddr)
   149  }
   150  ```
   151  
   152  Note, the slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module
   153  that emits informative events and finally delegates calls to the `x/staking` module. See documentation
   154  on slashing and jailing in [x/staking spec](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md).