mukan-sdk/x/slashing/keeper/infractions.go
Mukan Erkin Törük 20afb5db80
Some checks failed
Build SimApp / build (amd64) (push) Waiting to run
Build SimApp / build (arm64) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
Build & Push / build (push) Waiting to run
Run Gosec / Gosec (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Checks dependencies and mocks generation / Check go mod tidy (push) Waiting to run
Checks dependencies and mocks generation / Check up to date mocks (push) Waiting to run
System Tests / setup (push) Waiting to run
System Tests / test-system (push) Blocked by required conditions
System Tests / test-system-legacy (push) Blocked by required conditions
Tests / Code Coverage / split-test-files (push) Waiting to run
Tests / Code Coverage / tests (00) (push) Blocked by required conditions
Tests / Code Coverage / tests (01) (push) Blocked by required conditions
Tests / Code Coverage / tests (02) (push) Blocked by required conditions
Tests / Code Coverage / tests (03) (push) Blocked by required conditions
Tests / Code Coverage / test-integration (push) Waiting to run
Tests / Code Coverage / test-e2e (push) Waiting to run
Tests / Code Coverage / repo-analysis (push) Blocked by required conditions
Tests / Code Coverage / test-sim-nondeterminism (push) Waiting to run
Tests / Code Coverage / test-clientv2 (push) Waiting to run
Tests / Code Coverage / test-core (push) Waiting to run
Tests / Code Coverage / test-depinject (push) Waiting to run
Tests / Code Coverage / test-errors (push) Waiting to run
Tests / Code Coverage / test-math (push) Waiting to run
Tests / Code Coverage / test-schema (push) Waiting to run
Tests / Code Coverage / test-collections (push) Waiting to run
Tests / Code Coverage / test-cosmovisor (push) Waiting to run
Tests / Code Coverage / test-confix (push) Waiting to run
Tests / Code Coverage / test-store (push) Waiting to run
Tests / Code Coverage / test-log (push) Waiting to run
Tests / Code Coverage / test-x-tx (push) Waiting to run
Tests / Code Coverage / test-x-nft (push) Waiting to run
Tests / Code Coverage / test-x-circuit (push) Waiting to run
Tests / Code Coverage / test-x-feegrant (push) Waiting to run
Tests / Code Coverage / test-x-evidence (push) Waiting to run
Tests / Code Coverage / test-x-upgrade (push) Waiting to run
Tests / Code Coverage / test-tools-benchmark (push) Waiting to run
Build & Push SDK Proto Builder / build (push) Has been cancelled
initial: sovereign Mukan Network fork
2026-05-11 03:18:24 +03:00

187 lines
5.9 KiB
Go

package keeper
import (
"context"
"fmt"
"github.com/cockroachdb/errors"
"cosmossdk.io/core/comet"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
// HandleValidatorSignature handles a validator signature, must be called once per validator per block.
func (k Keeper) HandleValidatorSignature(ctx context.Context, addr cryptotypes.Address, power int64, signed comet.BlockIDFlag) error {
sdkCtx := sdk.UnwrapSDKContext(ctx)
logger := k.Logger(ctx)
height := sdkCtx.BlockHeight()
// fetch the validator public key
consAddr := sdk.ConsAddress(addr)
// don't update missed blocks when validator's jailed
isJailed, err := k.sk.IsValidatorJailed(ctx, consAddr)
if err != nil {
return err
}
if isJailed {
return nil
}
// fetch signing info
signInfo, err := k.GetValidatorSigningInfo(ctx, consAddr)
if err != nil {
return err
}
signedBlocksWindow, err := k.SignedBlocksWindow(ctx)
if err != nil {
return err
}
// Compute the relative index, so we count the blocks the validator *should*
// have signed. We will use the 0-value default signing info if not present,
// except for start height. The index is in the range [0, SignedBlocksWindow)
// and is used to see if a validator signed a block at the given height, which
// is represented by a bit in the bitmap.
index := signInfo.IndexOffset % signedBlocksWindow
signInfo.IndexOffset++
// determine if the validator signed the previous block
previous, err := k.GetMissedBlockBitmapValue(ctx, consAddr, index)
if err != nil {
return errors.Wrap(err, "failed to get the validator's bitmap value")
}
missed := signed == comet.BlockIDFlagAbsent
switch {
case !previous && missed:
// Bitmap value has changed from not missed to missed, so we flip the bit
// and increment the counter.
if err := k.SetMissedBlockBitmapValue(ctx, consAddr, index, true); err != nil {
return err
}
signInfo.MissedBlocksCounter++
case previous && !missed:
// Bitmap value has changed from missed to not missed, so we flip the bit
// and decrement the counter.
if err := k.SetMissedBlockBitmapValue(ctx, consAddr, index, false); err != nil {
return err
}
signInfo.MissedBlocksCounter--
default:
// bitmap value at this index has not changed, no need to update counter
}
minSignedPerWindow, err := k.MinSignedPerWindow(ctx)
if err != nil {
return err
}
if missed {
sdkCtx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeLiveness,
sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()),
sdk.NewAttribute(types.AttributeKeyMissedBlocks, fmt.Sprintf("%d", signInfo.MissedBlocksCounter)),
sdk.NewAttribute(types.AttributeKeyHeight, fmt.Sprintf("%d", height)),
),
)
logger.Debug(
"absent validator",
"height", height,
"validator", consAddr.String(),
"missed", signInfo.MissedBlocksCounter,
"threshold", minSignedPerWindow,
)
}
minHeight := signInfo.StartHeight + signedBlocksWindow
maxMissed := signedBlocksWindow - minSignedPerWindow
// if we are past the minimum height and the validator has missed too many blocks, punish them
if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {
validator, err := k.sk.ValidatorByConsAddr(ctx, consAddr)
if err != nil {
return err
}
if validator != nil && !validator.IsJailed() {
// Downtime confirmed: slash and jail the validator
// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height,
// and subtract an additional 1 since this is the LastCommit.
// Note that this *can* result in a negative "distributionHeight" up to -ValidatorUpdateDelay-1,
// i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block.
// That's fine since this is just used to filter unbonding delegations & redelegations.
distributionHeight := height - sdk.ValidatorUpdateDelay - 1
slashFractionDowntime, err := k.SlashFractionDowntime(ctx)
if err != nil {
return err
}
coinsBurned, err := k.sk.SlashWithInfractionReason(ctx, consAddr, distributionHeight, power, slashFractionDowntime, stakingtypes.Infraction_INFRACTION_DOWNTIME)
if err != nil {
return err
}
sdkCtx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeSlash,
sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()),
sdk.NewAttribute(types.AttributeKeyPower, fmt.Sprintf("%d", power)),
sdk.NewAttribute(types.AttributeKeyReason, types.AttributeValueMissingSignature),
sdk.NewAttribute(types.AttributeKeyJailed, consAddr.String()),
sdk.NewAttribute(types.AttributeKeyBurnedCoins, coinsBurned.String()),
),
)
if err := k.sk.Jail(sdkCtx, consAddr); err != nil {
return fmt.Errorf("failed to jail validator: %w", err)
}
downtimeJailDur, err := k.DowntimeJailDuration(ctx)
if err != nil {
return err
}
signInfo.JailedUntil = sdkCtx.BlockHeader().Time.Add(downtimeJailDur)
// We need to reset the counter & bitmap so that the validator won't be
// immediately slashed for downtime upon re-bonding.
signInfo.MissedBlocksCounter = 0
signInfo.IndexOffset = 0
err = k.DeleteMissedBlockBitmap(ctx, consAddr)
if err != nil {
return err
}
logger.Info(
"slashing and jailing validator due to liveness fault",
"height", height,
"validator", consAddr.String(),
"min_height", minHeight,
"threshold", minSignedPerWindow,
"slashed", slashFractionDowntime.String(),
"jailed_until", signInfo.JailedUntil,
)
} else {
// validator was (a) not found or (b) already jailed so we do not slash
logger.Info(
"validator would have been slashed for downtime, but was either not found in store or already jailed",
"validator", consAddr.String(),
)
}
}
// Set the updated signing info
return k.SetValidatorSigningInfo(ctx, consAddr, signInfo)
}