Merge PR #4826: ADR 009: Evidence Module
This commit is contained in:
parent
b9490f2d93
commit
1edecb8df5
|
@ -27,6 +27,7 @@ Please add a entry below in your Pull Request for an ADR.
|
|||
|
||||
- [ADR 002: SDK Documentation Structure](./adr-002-docs-structure.md)
|
||||
- [ADR 006: Secret Store Replacement](./adr-006-secret-store-replacement.md)
|
||||
- [ADR 009: Evidence Module](./adr-009-evidence-module.md)
|
||||
- [ADR 010: Modular AnteHandler](./adr-010-modular-antehandler.md)
|
||||
- [ADR 011: Generalize Genesis Accounts](./adr-011-generalize-genesis-accounts.md)
|
||||
- [ADR 012: State Accessors](./adr-012-state-accessors.md)
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
# ADR 009: Evidence Module
|
||||
|
||||
## Changelog
|
||||
|
||||
- 2019 July 31: Initial draft
|
||||
|
||||
## Status
|
||||
|
||||
Proposed
|
||||
|
||||
## Context
|
||||
|
||||
In order to support building highly secure, robust and interoperable blockchain
|
||||
applications, it is vital for the Cosmos SDK to expose a mechanism in which arbitrary
|
||||
evidence can be submitted, evaluated and verified resulting in some agreed upon
|
||||
penalty for any misbehavior committed by a validator, such as equivocation (double-voting),
|
||||
signing when unbonded, signing an incorrect state transition (in the future), etc.
|
||||
Furthermore, such a mechanism is paramount for any
|
||||
[IBC](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_ARCHITECTURE.md) or
|
||||
cross-chain validation protocol implementation in order to support the ability
|
||||
for any misbehavior to be relayed back from a collateralized chain to a primary
|
||||
chain so that the equivocating validator(s) can be slashed.
|
||||
|
||||
## Decision
|
||||
|
||||
We will implement an evidence module in the Cosmos SDK supporting the following
|
||||
functionality:
|
||||
|
||||
- Provide developers with the abstractions and interfaces necessary to define
|
||||
custom evidence messages, message handlers, and methods to slash and penalize
|
||||
accordingly for misbehavior.
|
||||
- Support the ability to route evidence messages to handlers in any module to
|
||||
determine the validity of submitted misbehavior.
|
||||
- Support the ability, through governance, to modify slashing penalties of any
|
||||
evidence type.
|
||||
- Querier implementation to support querying params, evidence types, params, and
|
||||
all submitted valid misbehavior.
|
||||
|
||||
### Types
|
||||
|
||||
First, we define the `Evidence` interface type. The `x/evidence` module may implement
|
||||
its own types that can be used by many chains (e.g. `CounterFactualEvidence`).
|
||||
In addition, other modules may implement their own `Evidence` types in a similar
|
||||
manner in which governance is extensible. It is important to note any concrete
|
||||
type implementing the `Evidence` interface may include arbitrary fields such as
|
||||
an infraction time. We want the `Evidence` type to remain as flexible as possible.
|
||||
|
||||
When submitting evidence to the `x/evidence` module, the concrete type must provide
|
||||
the validator's consensus address, which should be known by the `x/slashing`
|
||||
module (assuming the infraction is valid), the height at which the infraction
|
||||
occurred and the validator's power at same height in which the infraction occurred.
|
||||
|
||||
```go
|
||||
type Evidence interface {
|
||||
Route() string
|
||||
Type() string
|
||||
String() string
|
||||
ValidateBasic() Error
|
||||
|
||||
// The consensus address of the malicious validator at time of infraction
|
||||
GetConsensusAddress() ConsAddress
|
||||
|
||||
// Height at which the infraction occurred
|
||||
GetHeight() int64
|
||||
|
||||
// The total power of the malicious validator at time of infraction
|
||||
GetValidatorPower() int64
|
||||
|
||||
// The total validator set power at time of infraction
|
||||
GetTotalPower() int64
|
||||
}
|
||||
```
|
||||
|
||||
### Routing & Handling
|
||||
|
||||
Each `Evidence` type must map to a specific unique route and be registered with
|
||||
the `x/evidence` module. It accomplishes this through the `Router` implementation.
|
||||
|
||||
```go
|
||||
type Router interface {
|
||||
AddRoute(r string, h Handler)
|
||||
HasRoute(r string) bool
|
||||
GetRoute(path string) Handler
|
||||
Seal()
|
||||
}
|
||||
```
|
||||
|
||||
Upon successful routing through the `x/evidence` module, the `Evidence` type
|
||||
is passed through a `Handler`. This `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.
|
||||
Since slashing fractions will typically result from some form of static functions,
|
||||
allow the `Handler` to do this provides the greatest flexibility. An example could
|
||||
be `k * evidence.GetValidatorPower()` where `k` is an on-chain parameter controlled
|
||||
by governance. The `Evidence` type should provide all the external information
|
||||
necessary in order for the `Handler` to make the necessary state transitions.
|
||||
If no error is returned, the `Evidence` is considered valid.
|
||||
|
||||
```go
|
||||
type Handler func(Context, Evidence) Error
|
||||
```
|
||||
|
||||
### Submission
|
||||
|
||||
`Evidence` is submitted through a `MsgSubmitEvidence` message type which is internally
|
||||
handled by the `x/evidence` module's `SubmitEvidence`.
|
||||
|
||||
```go
|
||||
type MsgSubmitEvidence struct {
|
||||
Evidence
|
||||
}
|
||||
|
||||
func handleMsgSubmitEvidence(ctx Context, keeper Keeper, msg MsgSubmitEvidence) Result {
|
||||
if err := keeper.SubmitEvidence(ctx, msg.Evidence); err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
// emit events...
|
||||
|
||||
return Result{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `x/evidence` module's keeper is responsible for matching the `Evidence` against
|
||||
the module's router and invoking the corresponding `Handler` which may include
|
||||
slashing and jailing the validator. Upon success, the submitted evidence is persisted.
|
||||
|
||||
```go
|
||||
func (k Keeper) SubmitEvidence(ctx Context, evidence Evidence) Error {
|
||||
handler := keeper.router.GetRoute(evidence.Route())
|
||||
if err := handler(ctx, evidence); err != nil {
|
||||
return ErrInvalidEvidence(keeper.codespace, err)
|
||||
}
|
||||
|
||||
keeper.setEvidence(ctx, evidence)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
### Genesis
|
||||
|
||||
Finally, we need to represent the genesis state of the `x/evidence` module. The
|
||||
module only needs a list of all submitted valid infractions and any necessary params
|
||||
for which the module needs in order to handle submitted evidence. The `x/evidence`
|
||||
module will naturally define and route native evidence types for which it'll most
|
||||
likely need slashing penalty constants for.
|
||||
|
||||
```go
|
||||
type GenesisState struct {
|
||||
Params Params
|
||||
Infractions []Evidence
|
||||
}
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- Allows the state machine to process misbehavior submitted on-chain and penalize
|
||||
validators based on agreed upon slashing parameters.
|
||||
- Allows evidence types to be defined and handled by any module. This further allows
|
||||
slashing and jailing to be defined by more complex mechanisms.
|
||||
- Does not solely rely on Tendermint to submit evidence.
|
||||
|
||||
### Negative
|
||||
|
||||
- No easy way to introduce new evidence types through governance on a live chain
|
||||
due to the inability to introduce the new evidence type's corresponding handler
|
||||
|
||||
### Neutral
|
||||
|
||||
- Should we persist infractions indefinitely? Or should we rather rely on events?
|
||||
|
||||
## References
|
||||
|
||||
- [ICS](https://github.com/cosmos/ics)
|
||||
- [IBC Architecture](https://github.com/cosmos/ics/blob/master/ibc/1_IBC_ARCHITECTURE.md)
|
Loading…
Reference in New Issue