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.

136 lines
4.5 KiB

  1. package state
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "github.com/tendermint/tendermint/types"
  7. )
  8. //-----------------------------------------------------
  9. // Validate block
  10. // ValidateBlock validates the block against the state.
  11. func ValidateBlock(s State, block *types.Block) error {
  12. return validateBlock(s, block)
  13. }
  14. func validateBlock(s State, b *types.Block) error {
  15. // validate internal consistency
  16. if err := b.ValidateBasic(); err != nil {
  17. return err
  18. }
  19. // validate basic info
  20. if b.ChainID != s.ChainID {
  21. return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v", s.ChainID, b.ChainID)
  22. }
  23. if b.Height != s.LastBlockHeight+1 {
  24. return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v", s.LastBlockHeight+1, b.Height)
  25. }
  26. /* TODO: Determine bounds for Time
  27. See blockchain/reactor "stopSyncingDurationMinutes"
  28. if !b.Time.After(lastBlockTime) {
  29. return errors.New("Invalid Block.Header.Time")
  30. }
  31. */
  32. // validate prev block info
  33. if !b.LastBlockID.Equals(s.LastBlockID) {
  34. return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.LastBlockID)
  35. }
  36. newTxs := int64(len(b.Data.Txs))
  37. if b.TotalTxs != s.LastBlockTotalTx+newTxs {
  38. return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.TotalTxs)
  39. }
  40. // validate app info
  41. if !bytes.Equal(b.AppHash, s.AppHash) {
  42. return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v", s.AppHash, b.AppHash)
  43. }
  44. if !bytes.Equal(b.ConsensusHash, s.ConsensusParams.Hash()) {
  45. return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v", s.ConsensusParams.Hash(), b.ConsensusHash)
  46. }
  47. if !bytes.Equal(b.LastResultsHash, s.LastResultsHash) {
  48. return fmt.Errorf("Wrong Block.Header.LastResultsHash. Expected %X, got %v", s.LastResultsHash, b.LastResultsHash)
  49. }
  50. if !bytes.Equal(b.ValidatorsHash, s.Validators.Hash()) {
  51. return fmt.Errorf("Wrong Block.Header.ValidatorsHash. Expected %X, got %v", s.Validators.Hash(), b.ValidatorsHash)
  52. }
  53. // Validate block LastCommit.
  54. if b.Height == 1 {
  55. if len(b.LastCommit.Precommits) != 0 {
  56. return errors.New("Block at height 1 (first block) should have no LastCommit precommits")
  57. }
  58. } else {
  59. if len(b.LastCommit.Precommits) != s.LastValidators.Size() {
  60. return fmt.Errorf("Invalid block commit size. Expected %v, got %v",
  61. s.LastValidators.Size(), len(b.LastCommit.Precommits))
  62. }
  63. err := s.LastValidators.VerifyCommit(
  64. s.ChainID, s.LastBlockID, b.Height-1, b.LastCommit)
  65. if err != nil {
  66. return err
  67. }
  68. }
  69. for _, ev := range b.Evidence.Evidence {
  70. if err := VerifyEvidence(s, ev); err != nil {
  71. return types.NewEvidenceInvalidErr(ev, err)
  72. }
  73. /* // Needs a db ...
  74. valset, err := LoadValidators(s.db, ev.Height())
  75. if err != nil {
  76. // XXX/TODO: what do we do if we can't load the valset?
  77. // eg. if we have pruned the state or height is too high?
  78. return err
  79. }
  80. if err := VerifyEvidenceValidator(valSet, ev); err != nil {
  81. return types.NewEvidenceInvalidErr(ev, err)
  82. }
  83. */
  84. }
  85. return nil
  86. }
  87. // XXX: What's cheaper (ie. what should be checked first):
  88. // evidence internal validity (ie. sig checks) or validator existed (fetch historical val set from db)
  89. // VerifyEvidence verifies the evidence fully by checking it is internally
  90. // consistent and sufficiently recent.
  91. func VerifyEvidence(s State, evidence types.Evidence) error {
  92. height := s.LastBlockHeight
  93. evidenceAge := height - evidence.Height()
  94. maxAge := s.ConsensusParams.EvidenceParams.MaxAge
  95. if evidenceAge > maxAge {
  96. return fmt.Errorf("Evidence from height %d is too old. Min height is %d",
  97. evidence.Height(), height-maxAge)
  98. }
  99. if err := evidence.Verify(s.ChainID); err != nil {
  100. return err
  101. }
  102. return nil
  103. }
  104. // VerifyEvidenceValidator returns the voting power of the validator at the height of the evidence.
  105. // It returns an error if the validator did not exist or does not match that loaded from the historical validator set.
  106. func VerifyEvidenceValidator(valset *types.ValidatorSet, evidence types.Evidence) (priority int64, err error) {
  107. // The address must have been an active validator at the height
  108. ev := evidence
  109. height, addr, idx := ev.Height(), ev.Address(), ev.Index()
  110. valIdx, val := valset.GetByAddress(addr)
  111. if val == nil {
  112. return priority, fmt.Errorf("Address %X was not a validator at height %d", addr, height)
  113. } else if idx != valIdx {
  114. return priority, fmt.Errorf("Address %X was validator %d at height %d, not %d", addr, valIdx, height, idx)
  115. }
  116. priority = val.VotingPower
  117. return priority, nil
  118. }