You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.0 KiB

  1. package evidence
  2. import (
  3. "fmt"
  4. sm "github.com/tendermint/tendermint/state"
  5. "github.com/tendermint/tendermint/types"
  6. )
  7. // VerifyEvidence verifies the evidence fully by checking:
  8. // - it is sufficiently recent (MaxAge)
  9. // - it is from a key who was a validator at the given height
  10. // - it is internally consistent
  11. // - it was properly signed by the alleged equivocator
  12. func VerifyEvidence(evidence types.Evidence, state sm.State, stateDB StateStore, blockStore BlockStore) error {
  13. var (
  14. height = state.LastBlockHeight
  15. evidenceParams = state.ConsensusParams.Evidence
  16. ageDuration = state.LastBlockTime.Sub(evidence.Time())
  17. ageNumBlocks = height - evidence.Height()
  18. header *types.Header
  19. )
  20. // if the evidence is from the current height - this means the evidence is fresh from the consensus
  21. // and we won't have it in the block store. We thus check that the time isn't before the previous block
  22. if evidence.Height() == height+1 {
  23. if evidence.Time().Before(state.LastBlockTime) {
  24. return fmt.Errorf("evidence is from an earlier time than the previous block: %v < %v",
  25. evidence.Time(),
  26. state.LastBlockTime)
  27. }
  28. } else {
  29. // try to retrieve header from blockstore
  30. blockMeta := blockStore.LoadBlockMeta(evidence.Height())
  31. header = &blockMeta.Header
  32. if header == nil {
  33. return fmt.Errorf("don't have header at height #%d", evidence.Height())
  34. }
  35. if header.Time != evidence.Time() {
  36. return fmt.Errorf("evidence time (%v) is different to the time of the header we have for the same height (%v)",
  37. evidence.Time(),
  38. header.Time,
  39. )
  40. }
  41. }
  42. if ageDuration > evidenceParams.MaxAgeDuration && ageNumBlocks > evidenceParams.MaxAgeNumBlocks {
  43. return fmt.Errorf(
  44. "evidence from height %d (created at: %v) is too old; min height is %d and evidence can not be older than %v",
  45. evidence.Height(),
  46. evidence.Time(),
  47. height-evidenceParams.MaxAgeNumBlocks,
  48. state.LastBlockTime.Add(evidenceParams.MaxAgeDuration),
  49. )
  50. }
  51. // If in the case of lunatic validator evidence we need our committed header again to verify the evidence
  52. if ev, ok := evidence.(*types.LunaticValidatorEvidence); ok {
  53. if err := ev.VerifyHeader(header); err != nil {
  54. return err
  55. }
  56. }
  57. valset, err := stateDB.LoadValidators(evidence.Height())
  58. if err != nil {
  59. return err
  60. }
  61. if ae, ok := evidence.(*types.AmnesiaEvidence); ok {
  62. // check the validator set against the polc to make sure that a majority of valid votes was reached
  63. if !ae.Polc.IsAbsent() {
  64. err = ae.Polc.ValidateVotes(valset, state.ChainID)
  65. if err != nil {
  66. return fmt.Errorf("amnesia evidence contains invalid polc, err: %w", err)
  67. }
  68. }
  69. }
  70. addr := evidence.Address()
  71. var val *types.Validator
  72. // For all other types, expect evidence.Address to be a validator at height
  73. // evidence.Height.
  74. _, val = valset.GetByAddress(addr)
  75. if val == nil {
  76. return fmt.Errorf("address %X was not a validator at height %d", addr, evidence.Height())
  77. }
  78. if err := evidence.Verify(state.ChainID, val.PubKey); err != nil {
  79. return err
  80. }
  81. return nil
  82. }