Documentation ¶
Overview ¶
Package evidence handles all evidence storage and gossiping from detection to block proposal. For the different types of evidence refer to the `evidence.go` file in the types package or https://github.com/tendermint/tendermint/blob/master/spec/consensus/light-client/accountability.md.
Gossiping ¶
The core functionality begins with the evidence reactor (see reactor. go) which operates both the sending and receiving of evidence.
The `Receive` function takes a list of evidence and does the following:
1. Checks that it does not already have the evidence stored
2. Verifies the evidence against the node's state (see state/validation.go#VerifyEvidence)
3. Stores the evidence to a db and a concurrent list
The gossiping of evidence is initiated when a peer is added which starts a go routine to broadcast currently uncommitted evidence at intervals of 60 seconds (set by the by broadcastEvidenceIntervalS). It uses a concurrent list to store the evidence and before sending verifies that each evidence is still valid in the sense that it has not exceeded the max evidence age and height (see types/params.go#EvidenceParams).
There are two buckets that evidence can be stored in: Pending & Committed.
1. Pending is awaiting to be committed (evidence is usually broadcasted then)
2. Committed is for those already on the block and is to ensure that evidence isn't submitted twice
All evidence is proto encoded to disk.
Proposing ¶
When a new block is being proposed (in state/execution.go#CreateProposalBlock), `PendingEvidence(maxBytes)` is called to send up to the maxBytes of uncommitted evidence, from the evidence store, prioritized in order of age. All evidence is checked for expiration.
When a node receives evidence in a block it will use the evidence module as a cache first to see if it has already verified the evidence before trying to verify it again.
Once the proposed evidence is submitted, the evidence is marked as committed and is moved from the broadcasted set to the committed set. As a result it is also removed from the concurrent list so that it is no longer gossiped.
Minor Functionality ¶
As all evidence (including POLC's) are bounded by an expiration date, those that exceed this are no longer needed and hence pruned. Currently, only committed evidence in which a marker to the height that the evidence was committed and hence very small is saved. All updates are made from the `Update(block, state)` function which should be called when a new block is committed.
Index ¶
- Constants
- func GetChannelDescriptor() *p2p.ChannelDescriptor
- func VerifyDuplicateVote(e *types.DuplicateVoteEvidence, chainID string, valSet *types.ValidatorSet, ...) error
- type BlockStore
- type Metrics
- type Pool
- func (evpool *Pool) AddEvidence(ctx context.Context, ev types.Evidence) error
- func (evpool *Pool) CheckEvidence(ctx context.Context, evList types.EvidenceList) error
- func (evpool *Pool) Close() error
- func (evpool *Pool) EvidenceFront() *clist.CElement
- func (evpool *Pool) EvidenceWaitChan() <-chan struct{}
- func (evpool *Pool) PendingEvidence(maxBytes int64) ([]types.Evidence, int64)
- func (evpool *Pool) ReportConflictingVotes(voteA, voteB *types.Vote)
- func (evpool *Pool) Size() uint32
- func (evpool *Pool) Start(state sm.State) error
- func (evpool *Pool) State() sm.State
- func (evpool *Pool) Update(ctx context.Context, state sm.State, ev types.EvidenceList)
- type Reactor
Constants ¶
const (
EvidenceChannel = p2p.ChannelID(0x38)
)
const ( // MetricsSubsystem is a subsystem shared by all metrics exposed by this // package. MetricsSubsystem = "evidence_pool" )
Variables ¶
This section is empty.
Functions ¶
func GetChannelDescriptor ¶
func GetChannelDescriptor() *p2p.ChannelDescriptor
GetChannelDescriptor produces an instance of a descriptor for this package's required channels.
func VerifyDuplicateVote ¶
func VerifyDuplicateVote(e *types.DuplicateVoteEvidence, chainID string, valSet *types.ValidatorSet, logger log.Logger) error
VerifyDuplicateVote verifies DuplicateVoteEvidence against the state of full node. This involves the following checks:
- the validator is in the validator set at the height of the evidence
- the height, round, type and validator address of the votes must be the same
- the block ID's must be different
- The signatures must both be valid (only if we have public keys of the validator set)
TODO: Double-check that this will still work for quite old heights, where validator set has already been rotated.
Types ¶
type BlockStore ¶
type Metrics ¶
type Metrics struct { // Number of pending evidence in the evidence pool. NumEvidence metrics.Gauge }
Metrics contains metrics exposed by this package. see MetricsProvider for descriptions.
func NopMetrics ¶
func NopMetrics() *Metrics
func PrometheusMetrics ¶
type Pool ¶
type Pool struct { Metrics *Metrics // contains filtered or unexported fields }
Pool maintains a pool of valid evidence to be broadcasted and committed
func NewPool ¶
func NewPool(logger log.Logger, evidenceDB dbm.DB, stateStore sm.Store, blockStore BlockStore, metrics *Metrics, eventBus *eventbus.EventBus) *Pool
NewPool creates an evidence pool. If using an existing evidence store, it will add all pending evidence to the concurrent list.
func (*Pool) AddEvidence ¶
AddEvidence checks the evidence is valid and adds it to the pool.
func (*Pool) CheckEvidence ¶
CheckEvidence takes an array of evidence from a block and verifies all the evidence there. If it has already verified the evidence then it jumps to the next one. It ensures that no evidence has already been committed or is being proposed twice. It also adds any evidence that it doesn't currently have so that it can quickly form ABCI Evidence later.
func (*Pool) EvidenceFront ¶
EvidenceFront goes to the first evidence in the clist
func (*Pool) EvidenceWaitChan ¶
func (evpool *Pool) EvidenceWaitChan() <-chan struct{}
EvidenceWaitChan is a channel that closes once the first evidence in the list is there. i.e Front is not nil.
func (*Pool) PendingEvidence ¶
PendingEvidence is used primarily as part of block proposal and returns up to maxNum of uncommitted evidence.
func (*Pool) ReportConflictingVotes ¶
ReportConflictingVotes takes two conflicting votes and forms duplicate vote evidence, adding it eventually to the evidence pool.
Duplicate vote attacks happen before the block is committed and the timestamp is finalized, thus the evidence pool holds these votes in a buffer, forming the evidence from them once consensus at that height has been reached and `Update()` with the new state called.
Votes are not verified.
func (*Pool) Update ¶
Update takes both the new state and the evidence committed at that height and performs the following operations:
- Take any conflicting votes from consensus and use the state's LastBlockTime to form DuplicateVoteEvidence and add it to the pool.
- Update the pool's state which contains evidence params relating to expiry.
- Moves pending evidence that has now been committed into the committed pool.
- Removes any expired evidence based on both height and time.
type Reactor ¶
type Reactor struct { service.BaseService // contains filtered or unexported fields }
Reactor handles evpool evidence broadcasting amongst peers.
func NewReactor ¶
func NewReactor( logger log.Logger, chCreator p2p.ChannelCreator, peerEvents p2p.PeerEventSubscriber, evpool *Pool, ) *Reactor
NewReactor returns a reference to a new evidence reactor, which implements the service.Service interface. It accepts a p2p Channel dedicated for handling envelopes with EvidenceList messages.
func (*Reactor) OnStart ¶
OnStart starts separate go routines for each p2p Channel and listens for envelopes on each. In addition, it also listens for peer updates and handles messages on that p2p channel accordingly. The caller must be sure to execute OnStop to ensure the outbound p2p Channels are closed. No error is returned.