evidence

package module
v0.0.0-...-095f669 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2023 License: Apache-2.0 Imports: 25 Imported by: 1

README


sidebar_position: 1

x/evidence

Abstract

x/evidence is an implementation of a Cosmos SDK module, per ADR 009, that allows for the submission and handling of arbitrary evidence of misbehavior such as equivocation and counterfactual signing.

The evidence module differs from standard evidence handling which typically expects the underlying consensus engine, e.g. CometBFT, to automatically submit evidence when it is discovered by allowing clients and foreign chains to submit more complex evidence directly.

All concrete evidence types must implement the Evidence interface contract. Submitted Evidence is first routed through the evidence module's Router in which it attempts to find a corresponding registered Handler for that specific Evidence type. Each Evidence type must have a Handler registered with the evidence module's keeper in order for it to be successfully routed and executed.

Each corresponding handler must also fulfill the Handler interface contract. The Handler for a given Evidence type can perform any arbitrary state transitions such as slashing, jailing, and tombstoning.

Concepts

Evidence

Any concrete type of evidence submitted to the x/evidence module must fulfill the Evidence contract outlined below. Not all concrete types of evidence will fulfill this contract in the same way and some data may be entirely irrelevant to certain types of evidence. An additional ValidatorEvidence, which extends Evidence, has also been created to define a contract for evidence against malicious validators.

// Evidence defines the contract which concrete evidence types of misbehavior
// must implement.
type Evidence interface {
	proto.Message

	Route() string
	String() string
	Hash() []byte
	ValidateBasic() error

	// Height at which the infraction occurred
	GetHeight() int64
}

// ValidatorEvidence extends Evidence interface to define contract
// for evidence against malicious validators
type ValidatorEvidence interface {
	Evidence

	// The consensus address of the malicious validator at time of infraction
	GetConsensusAddress() sdk.ConsAddress

	// The total power of the malicious validator at time of infraction
	GetValidatorPower() int64

	// The total validator set power at time of infraction
	GetTotalPower() int64
}

Registration & Handling

The x/evidence module must first know about all types of evidence it is expected to handle. This is accomplished by registering the Route method in the Evidence contract with what is known as a Router (defined below). The Router accepts Evidence and attempts to find the corresponding Handler for the Evidence via the Route method.

type Router interface {
  AddRoute(r string, h Handler) Router
  HasRoute(r string) bool
  GetRoute(path string) Handler
  Seal()
  Sealed() bool
}

The Handler (defined below) is responsible for executing the entirety of the business logic for handling Evidence. This typically includes validating the evidence, both stateless checks via ValidateBasic and stateful checks via any keepers provided to the Handler. In addition, the Handler may also perform capabilities such as slashing and jailing a validator. All Evidence handled by the Handler should be persisted.

// Handler defines an agnostic Evidence handler. The handler is responsible
// for executing all corresponding business logic necessary for verifying the
// evidence as valid. In addition, the Handler may execute any necessary
// slashing and potential jailing.
type Handler func(sdk.Context, Evidence) error

State

Currently the x/evidence module only stores valid submitted Evidence in state. The evidence state is also stored and exported in the x/evidence module's GenesisState.

// GenesisState defines the evidence module's genesis state.
message GenesisState {
  // evidence defines all the evidence at genesis.
  repeated google.protobuf.Any evidence = 1;
}

All Evidence is retrieved and stored via a prefix KVStore using prefix 0x00 (KeyPrefixEvidence).

Messages

MsgSubmitEvidence

Evidence is submitted through a MsgSubmitEvidence message:

// MsgSubmitEvidence represents a message that supports submitting arbitrary
// Evidence of misbehavior such as equivocation or counterfactual signing.
message MsgSubmitEvidence {
  string              submitter = 1;
  google.protobuf.Any evidence  = 2;
}

Note, the Evidence of a MsgSubmitEvidence message must have a corresponding Handler registered with the x/evidence module's Router in order to be processed and routed correctly.

Given the Evidence is registered with a corresponding Handler, it is processed as follows:

func SubmitEvidence(ctx Context, evidence Evidence) error {
  if _, ok := GetEvidence(ctx, evidence.Hash()); ok {
    return errorsmod.Wrap(types.ErrEvidenceExists, strings.ToUpper(hex.EncodeToString(evidence.Hash())))
  }
  if !router.HasRoute(evidence.Route()) {
    return errorsmod.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route())
  }

  handler := router.GetRoute(evidence.Route())
  if err := handler(ctx, evidence); err != nil {
    return errorsmod.Wrap(types.ErrInvalidEvidence, err.Error())
  }

  ctx.EventManager().EmitEvent(
		sdk.NewEvent(
			types.EventTypeSubmitEvidence,
			sdk.NewAttribute(types.AttributeKeyEvidenceHash, strings.ToUpper(hex.EncodeToString(evidence.Hash()))),
		),
	)

  SetEvidence(ctx, evidence)
  return nil
}

First, there must not already exist valid submitted Evidence of the exact same type. Secondly, the Evidence is routed to the Handler and executed. Finally, if there is no error in handling the Evidence, an event is emitted and it is persisted to state.

Events

The x/evidence module emits the following events:

Handlers

MsgSubmitEvidence
Type Attribute Key Attribute Value
submit_evidence evidence_hash {evidenceHash}
message module evidence
message sender {senderAddress}
message action submit_evidence

Parameters

The evidence module does not contain any parameters.

BeginBlock

Evidence Handling

CometBFT blocks can include 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.

Equivocation

The Cosmos SDK handles two types of evidence inside the ABCI BeginBlock:

  • DuplicateVoteEvidence,
  • LightClientAttackEvidence.

The evidence module handles these two evidence types the same way. First, the Cosmos SDK converts the CometBFT concrete evidence type to an SDK Evidence interface using Equivocation as the concrete type.

https://github.com/verzth/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/evidence/v1beta1/evidence.proto#L12-L32

For some Equivocation submitted in block to be valid, it must satisfy:

Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge

Where:

  • Evidence.Timestamp is the timestamp in the block at height Evidence.Height
  • block.Timestamp is the current block timestamp.

If valid Equivocation evidence is included in a block, the validator's stake is reduced (slashed) by SlashFractionDoubleSign as defined by the x/slashing module of what their stake was when the infraction occurred, rather than when the evidence was discovered. We want to "follow the stake", i.e., the stake that contributed to the infraction should be slashed, even if it has since been redelegated or started unbonding.

In addition, the validator is permanently jailed and tombstoned to make it impossible for that validator to ever re-enter the validator set.

The Equivocation evidence is handled as follows:

https://github.com/verzth/cosmos-sdk/blob/v0.47.0-rc1/x/evidence/keeper/infraction.go#L26-L140

Note: The slashing, jailing, and tombstoning calls are delegated through the x/slashing module that emits informative events and finally delegates calls to the x/staking module. See documentation on slashing and jailing in State Transitions.

Client

CLI

A user can query and interact with the evidence module using the CLI.

Query

The query commands allows users to query evidence state.

simd query evidence --help
evidence

The evidence command allows users to list all evidence or evidence by hash.

Usage:

simd query evidence [flags]

To query evidence by hash

Example:

simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"

Example Output:

evidence:
  consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
  height: 11
  power: 100
  time: "2021-10-20T16:08:38.194017624Z"

To get all evidence

Example:

simd query evidence

Example Output:

evidence:
  consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h
  height: 11
  power: 100
  time: "2021-10-20T16:08:38.194017624Z"
pagination:
  next_key: null
  total: "1"

REST

A user can query the evidence module using REST endpoints.

Evidence

Get evidence by hash

/cosmos/evidence/v1beta1/evidence/{hash}

Example:

curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"

Example Output:

{
  "evidence": {
    "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
    "height": "11",
    "power": "100",
    "time": "2021-10-20T16:08:38.194017624Z"
  }
}
All evidence

Get all evidence

/cosmos/evidence/v1beta1/evidence

Example:

curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence"

Example Output:

{
  "evidence": [
    {
      "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
      "height": "11",
      "power": "100",
      "time": "2021-10-20T16:08:38.194017624Z"
    }
  ],
  "pagination": {
    "total": "1"
  }
}

gRPC

A user can query the evidence module using gRPC endpoints.

Evidence

Get evidence by hash

cosmos.evidence.v1beta1.Query/Evidence

Example:

grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence

Example Output:

{
  "evidence": {
    "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
    "height": "11",
    "power": "100",
    "time": "2021-10-20T16:08:38.194017624Z"
  }
}
All evidence

Get all evidence

cosmos.evidence.v1beta1.Query/AllEvidence

Example:

grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence

Example Output:

{
  "evidence": [
    {
      "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h",
      "height": "11",
      "power": "100",
      "time": "2021-10-20T16:08:38.194017624Z"
    }
  ],
  "pagination": {
    "total": "1"
  }
}

Documentation

Overview

Package evidence implements a Cosmos SDK module, per ADR 009, that allows for the submission and handling of arbitrary evidence of misbehavior.

All concrete evidence types must implement the Evidence interface contract. Submitted evidence is first routed through the evidence module's Router in which it attempts to find a corresponding Handler for that specific evidence type. Each evidence type must have a Handler registered with the evidence module's keeper in order for it to be successfully executed.

Each corresponding handler must also fulfill the Handler interface contract. The Handler for a given Evidence type can perform any arbitrary state transitions such as slashing, jailing, and tombstoning. This provides developers with great flexibility in designing evidence handling.

A full setup of the evidence module may look something as follows:

ModuleBasics = module.NewBasicManager(
  // ...,
  evidence.AppModuleBasic{},
)

// First, create the keeper
evidenceKeeper := evidence.NewKeeper(
  appCodec, keys[evidence.StoreKey], &app.StakingKeeper, app.SlashingKeeper,
)

// Second, create the evidence Handler and register all desired routes.
evidenceRouter := evidence.NewRouter().
  AddRoute(evidenceRoute, evidenceHandler).
  AddRoute(..., ...)

evidenceKeeper.SetRouter(evidenceRouter)

app.EvidenceKeeper = *evidenceKeeper

app.mm = module.NewManager(
  // ...
  evidence.NewAppModule(app.EvidenceKeeper),
)

// Remaining application bootstrapping...

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BeginBlocker

func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper)

BeginBlocker iterates through and handles any newly discovered evidence of misbehavior submitted by CometBFT. Currently, only equivocation is handled.

func ExportGenesis

func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState

ExportGenesis returns the evidence module's exported genesis.

func InitGenesis

func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs *types.GenesisState)

InitGenesis initializes the evidence module's state from a provided genesis state.

Types

type AppModule

type AppModule struct {
	AppModuleBasic
	// contains filtered or unexported fields
}

AppModule implements the AppModule interface for the evidence module.

func NewAppModule

func NewAppModule(keeper keeper.Keeper) AppModule

NewAppModule creates a new AppModule object.

func (AppModule) BeginBlock

func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock)

BeginBlock executes all ABCI BeginBlock logic respective to the evidence module.

func (AppModule) ConsensusVersion

func (AppModule) ConsensusVersion() uint64

ConsensusVersion implements AppModule/ConsensusVersion.

func (AppModule) ExportGenesis

func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage

ExportGenesis returns the evidence module's exported genesis state as raw JSON bytes.

func (AppModule) GenerateGenesisState

func (AppModule) GenerateGenesisState(simState *module.SimulationState)

GenerateGenesisState creates a randomized GenState of the evidence module.

func (AppModule) InitGenesis

func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate

InitGenesis performs the evidence module's genesis initialization It returns no validator updates.

func (AppModule) IsAppModule

func (am AppModule) IsAppModule()

IsAppModule implements the appmodule.AppModule interface.

func (AppModule) IsOnePerModuleType

func (am AppModule) IsOnePerModuleType()

IsOnePerModuleType implements the depinject.OnePerModuleType interface.

func (AppModule) Name

func (am AppModule) Name() string

Name returns the evidence module's name.

func (AppModule) RegisterInvariants

func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry)

RegisterInvariants registers the evidence module's invariants.

func (AppModule) RegisterServices

func (am AppModule) RegisterServices(cfg module.Configurator)

RegisterServices registers module services.

func (AppModule) RegisterStoreDecoder

func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry)

RegisterStoreDecoder registers a decoder for evidence module's types

func (AppModule) WeightedOperations

func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation

WeightedOperations returns the all the gov module operations with their respective weights.

type AppModuleBasic

type AppModuleBasic struct {
	// contains filtered or unexported fields
}

AppModuleBasic implements the AppModuleBasic interface for the evidence module.

func NewAppModuleBasic

func NewAppModuleBasic(evidenceHandlers ...eviclient.EvidenceHandler) AppModuleBasic

NewAppModuleBasic creates a AppModuleBasic without the codec.

func (AppModuleBasic) DefaultGenesis

func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage

DefaultGenesis returns the evidence module's default genesis state.

func (AppModuleBasic) GetQueryCmd

func (AppModuleBasic) GetQueryCmd() *cobra.Command

GetQueryCmd returns the evidence module's root query command.

func (AppModuleBasic) GetTxCmd

func (a AppModuleBasic) GetTxCmd() *cobra.Command

GetTxCmd returns the evidence module's root tx command.

func (AppModuleBasic) Name

func (AppModuleBasic) Name() string

Name returns the evidence module's name.

func (AppModuleBasic) RegisterGRPCGatewayRoutes

func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwruntime.ServeMux)

RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the evidence module.

func (AppModuleBasic) RegisterInterfaces

func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry)

RegisterInterfaces registers the evidence module's interface types

func (AppModuleBasic) RegisterLegacyAminoCodec

func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)

RegisterLegacyAminoCodec registers the evidence module's types to the LegacyAmino codec.

func (AppModuleBasic) ValidateGenesis

func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error

ValidateGenesis performs genesis state validation for the evidence module.

type EvidenceInputs

type EvidenceInputs struct {
	depinject.In

	Key *store.KVStoreKey
	Cdc codec.Codec

	StakingKeeper  types.StakingKeeper
	SlashingKeeper types.SlashingKeeper
}

type EvidenceOutputs

type EvidenceOutputs struct {
	depinject.Out

	EvidenceKeeper keeper.Keeper
	Module         appmodule.AppModule
}

func ProvideModule

func ProvideModule(in EvidenceInputs) EvidenceOutputs

Directories

Path Synopsis
cli
Package testutil is a generated GoMock package.
Package testutil is a generated GoMock package.
Package types is a reverse proxy.
Package types is a reverse proxy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL