mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-21 07:24:36 +00:00
evidence: modularise evidence by moving verification function into evidence package (#5234)
This commit is contained in:
+7
-104
@@ -144,50 +144,23 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
|
||||
block.Height, state.InitialHeight)
|
||||
}
|
||||
|
||||
// Limit the amount of evidence
|
||||
numEvidence := len(block.Evidence.Evidence)
|
||||
// MaxNumEvidence is capped at uint16, so conversion is always safe.
|
||||
if maxEvidence := int(state.ConsensusParams.Evidence.MaxNum); numEvidence > maxEvidence {
|
||||
return types.NewErrEvidenceOverflow(maxEvidence, numEvidence)
|
||||
// Check evidence doesn't exceed the limit. MaxNumEvidence is capped at uint16, so conversion is always safe.
|
||||
if max, got := int(state.ConsensusParams.Evidence.MaxNum), len(block.Evidence.Evidence); got > max {
|
||||
return types.NewErrEvidenceOverflow(max, got)
|
||||
}
|
||||
|
||||
// Validate all evidence.
|
||||
for idx, ev := range block.Evidence.Evidence {
|
||||
// check that no evidence has been submitted more than once
|
||||
// Check that no evidence has been submitted more than once
|
||||
for i := idx + 1; i < len(block.Evidence.Evidence); i++ {
|
||||
if ev.Equal(block.Evidence.Evidence[i]) {
|
||||
return types.NewErrEvidenceInvalid(ev, errors.New("evidence was submitted twice"))
|
||||
}
|
||||
}
|
||||
if evidencePool != nil {
|
||||
if evidencePool.IsCommitted(ev) {
|
||||
return types.NewErrEvidenceInvalid(ev, errors.New("evidence was already committed"))
|
||||
}
|
||||
if evidencePool.IsPending(ev) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// if we don't already have amnesia evidence we need to add it to start our own trial period unless
|
||||
// a) a valid polc has already been attached
|
||||
// b) the accused node voted back on an earlier round
|
||||
if ae, ok := ev.(*types.AmnesiaEvidence); ok && ae.Polc.IsAbsent() && ae.PotentialAmnesiaEvidence.VoteA.Round <
|
||||
ae.PotentialAmnesiaEvidence.VoteB.Round {
|
||||
if err := evidencePool.AddEvidence(ae.PotentialAmnesiaEvidence); err != nil {
|
||||
return types.NewErrEvidenceInvalid(ev,
|
||||
fmt.Errorf("unknown amnesia evidence, trying to add to evidence pool, err: %w", err))
|
||||
}
|
||||
return types.NewErrEvidenceInvalid(ev, errors.New("amnesia evidence is new and hasn't undergone trial period yet"))
|
||||
}
|
||||
|
||||
// A header needs to be fetched. For lunatic evidence this is so we can verify
|
||||
// that some of the fields are different to the ones we have. For all evidence it
|
||||
// it so we can verify that the time of the evidence is correct
|
||||
header := evidencePool.Header(ev.Height())
|
||||
if header == nil {
|
||||
return fmt.Errorf("don't have block meta at height #%d", ev.Height())
|
||||
}
|
||||
|
||||
if err := VerifyEvidence(stateDB, state, ev, header); err != nil {
|
||||
// Verify evidence using the evidence pool
|
||||
err := evidencePool.Verify(ev)
|
||||
if err != nil {
|
||||
return types.NewErrEvidenceInvalid(ev, err)
|
||||
}
|
||||
|
||||
@@ -195,73 +168,3 @@ func validateBlock(evidencePool EvidencePool, stateDB dbm.DB, state State, block
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyEvidence verifies the evidence fully by checking:
|
||||
// - it is sufficiently recent (MaxAge)
|
||||
// - it is from a key who was a validator at the given height
|
||||
// - it is internally consistent
|
||||
// - it was properly signed by the alleged equivocator
|
||||
func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence, committedHeader *types.Header) error {
|
||||
var (
|
||||
height = state.LastBlockHeight
|
||||
evidenceParams = state.ConsensusParams.Evidence
|
||||
|
||||
ageDuration = state.LastBlockTime.Sub(evidence.Time())
|
||||
ageNumBlocks = height - evidence.Height()
|
||||
)
|
||||
|
||||
if committedHeader.Time != evidence.Time() {
|
||||
return fmt.Errorf("evidence time (%v) is different to the time of the header we have for the same height (%v)",
|
||||
evidence.Time(),
|
||||
committedHeader.Time,
|
||||
)
|
||||
}
|
||||
|
||||
if ageDuration > evidenceParams.MaxAgeDuration && ageNumBlocks > evidenceParams.MaxAgeNumBlocks {
|
||||
return fmt.Errorf(
|
||||
"evidence from height %d (created at: %v) is too old; min height is %d and evidence can not be older than %v",
|
||||
evidence.Height(),
|
||||
evidence.Time(),
|
||||
height-evidenceParams.MaxAgeNumBlocks,
|
||||
state.LastBlockTime.Add(evidenceParams.MaxAgeDuration),
|
||||
)
|
||||
}
|
||||
if ev, ok := evidence.(*types.LunaticValidatorEvidence); ok {
|
||||
if err := ev.VerifyHeader(committedHeader); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
valset, err := LoadValidators(stateDB, evidence.Height())
|
||||
if err != nil {
|
||||
// TODO: if err is just that we cant find it cuz we pruned, ignore.
|
||||
// TODO: if its actually bad evidence, punish peer
|
||||
return err
|
||||
}
|
||||
|
||||
addr := evidence.Address()
|
||||
var val *types.Validator
|
||||
|
||||
if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
|
||||
// check the validator set against the polc to make sure that a majority of valid votes was reached
|
||||
if !ae.Polc.IsAbsent() {
|
||||
err = ae.Polc.ValidateVotes(valset, state.ChainID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For all other types, expect evidence.Address to be a validator at height
|
||||
// evidence.Height.
|
||||
_, val = valset.GetByAddress(addr)
|
||||
if val == nil {
|
||||
return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
|
||||
}
|
||||
|
||||
if err := evidence.Verify(state.ChainID, val.PubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user