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.

424 lines
13 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/tendermint/tendermint/crypto/merkle"
  10. "github.com/tendermint/tendermint/crypto/tmhash"
  11. tmjson "github.com/tendermint/tendermint/libs/json"
  12. tmrand "github.com/tendermint/tendermint/libs/rand"
  13. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  14. )
  15. // Evidence represents any provable malicious activity by a validator.
  16. // Verification logic for each evidence is part of the evidence module.
  17. type Evidence interface {
  18. Height() int64 // height of the infraction
  19. Bytes() []byte // bytes which comprise the evidence
  20. Hash() []byte // hash of the evidence
  21. ValidateBasic() error // basic consistency check
  22. String() string // string format of the evidence
  23. }
  24. //--------------------------------------------------------------------------------------
  25. // DuplicateVoteEvidence contains evidence a validator signed two conflicting
  26. // votes.
  27. type DuplicateVoteEvidence struct {
  28. VoteA *Vote `json:"vote_a"`
  29. VoteB *Vote `json:"vote_b"`
  30. }
  31. var _ Evidence = &DuplicateVoteEvidence{}
  32. // NewDuplicateVoteEvidence creates DuplicateVoteEvidence with right ordering given
  33. // two conflicting votes. If one of the votes is nil, evidence returned is nil as well
  34. func NewDuplicateVoteEvidence(vote1, vote2 *Vote) *DuplicateVoteEvidence {
  35. var voteA, voteB *Vote
  36. if vote1 == nil || vote2 == nil {
  37. return nil
  38. }
  39. if strings.Compare(vote1.BlockID.Key(), vote2.BlockID.Key()) == -1 {
  40. voteA = vote1
  41. voteB = vote2
  42. } else {
  43. voteA = vote2
  44. voteB = vote1
  45. }
  46. return &DuplicateVoteEvidence{
  47. VoteA: voteA,
  48. VoteB: voteB,
  49. }
  50. }
  51. // String returns a string representation of the evidence.
  52. func (dve *DuplicateVoteEvidence) String() string {
  53. return fmt.Sprintf("DuplicateVoteEvidence{VoteA: %v, VoteB: %v}", dve.VoteA, dve.VoteB)
  54. }
  55. // Height returns the height this evidence refers to.
  56. func (dve *DuplicateVoteEvidence) Height() int64 {
  57. return dve.VoteA.Height
  58. }
  59. // Bytes returns the proto-encoded evidence as a byte array.
  60. func (dve *DuplicateVoteEvidence) Bytes() []byte {
  61. pbe := dve.ToProto()
  62. bz, err := pbe.Marshal()
  63. if err != nil {
  64. panic(err)
  65. }
  66. return bz
  67. }
  68. // Hash returns the hash of the evidence.
  69. func (dve *DuplicateVoteEvidence) Hash() []byte {
  70. return tmhash.Sum(dve.Bytes())
  71. }
  72. // ValidateBasic performs basic validation.
  73. func (dve *DuplicateVoteEvidence) ValidateBasic() error {
  74. if dve == nil {
  75. return errors.New("empty duplicate vote evidence")
  76. }
  77. if dve.VoteA == nil || dve.VoteB == nil {
  78. return fmt.Errorf("one or both of the votes are empty %v, %v", dve.VoteA, dve.VoteB)
  79. }
  80. if err := dve.VoteA.ValidateBasic(); err != nil {
  81. return fmt.Errorf("invalid VoteA: %w", err)
  82. }
  83. if err := dve.VoteB.ValidateBasic(); err != nil {
  84. return fmt.Errorf("invalid VoteB: %w", err)
  85. }
  86. // Enforce Votes are lexicographically sorted on blockID
  87. if strings.Compare(dve.VoteA.BlockID.Key(), dve.VoteB.BlockID.Key()) >= 0 {
  88. return errors.New("duplicate votes in invalid order")
  89. }
  90. return nil
  91. }
  92. // ToProto encodes DuplicateVoteEvidence to protobuf
  93. func (dve *DuplicateVoteEvidence) ToProto() *tmproto.DuplicateVoteEvidence {
  94. voteB := dve.VoteB.ToProto()
  95. voteA := dve.VoteA.ToProto()
  96. tp := tmproto.DuplicateVoteEvidence{
  97. VoteA: voteA,
  98. VoteB: voteB,
  99. }
  100. return &tp
  101. }
  102. // DuplicateVoteEvidenceFromProto decodes protobuf into DuplicateVoteEvidence
  103. func DuplicateVoteEvidenceFromProto(pb *tmproto.DuplicateVoteEvidence) (*DuplicateVoteEvidence, error) {
  104. if pb == nil {
  105. return nil, errors.New("nil duplicate vote evidence")
  106. }
  107. vA, err := VoteFromProto(pb.VoteA)
  108. if err != nil {
  109. return nil, err
  110. }
  111. vB, err := VoteFromProto(pb.VoteB)
  112. if err != nil {
  113. return nil, err
  114. }
  115. dve := NewDuplicateVoteEvidence(vA, vB)
  116. return dve, dve.ValidateBasic()
  117. }
  118. //------------------------------------ LIGHT EVIDENCE --------------------------------------
  119. // LightClientAttackEvidence is a generalized evidence that captures all forms of known attacks on
  120. // a light client such that a full node can verify, propose and commit the evidence on-chain for
  121. // punishment of the malicious validators. There are three forms of attacks: Lunatic, Equivocation
  122. // and Amnesia. These attacks are exhaustive. You can find a more detailed overview of this at
  123. // tendermint/docs/architecture/adr-047-handling-evidence-from-light-client.md
  124. type LightClientAttackEvidence struct {
  125. ConflictingBlock *LightBlock
  126. CommonHeight int64
  127. }
  128. var _ Evidence = &LightClientAttackEvidence{}
  129. // Height returns the last height at which the primary provider and witness provider had the same header.
  130. // We use this as the height of the infraction rather than the actual conflicting header because we know
  131. // that the malicious validators were bonded at this height which is important for evidence expiry
  132. func (l *LightClientAttackEvidence) Height() int64 {
  133. return l.CommonHeight
  134. }
  135. // Bytes returns the proto-encoded evidence as a byte array
  136. func (l *LightClientAttackEvidence) Bytes() []byte {
  137. pbe, err := l.ToProto()
  138. if err != nil {
  139. panic(err)
  140. }
  141. bz, err := pbe.Marshal()
  142. if err != nil {
  143. panic(err)
  144. }
  145. return bz
  146. }
  147. // Hash returns the hash of the header and the commonHeight. This is designed to cause hash collisions with evidence
  148. // that have the same conflicting header and common height but different permutations of validator commit signatures.
  149. // The reason for this is that we don't want to allow several permutations of the same evidence to be committed on
  150. // chain. Ideally we commit the header with the most commit signatures but anything greater than 1/3 is sufficient.
  151. func (l *LightClientAttackEvidence) Hash() []byte {
  152. buf := make([]byte, binary.MaxVarintLen64)
  153. n := binary.PutVarint(buf, l.CommonHeight)
  154. bz := make([]byte, tmhash.Size+n)
  155. copy(bz[:tmhash.Size-1], l.ConflictingBlock.Hash().Bytes())
  156. copy(bz[tmhash.Size:], buf)
  157. return tmhash.Sum(bz)
  158. }
  159. // ValidateBasic performs basic validation such that the evidence is consistent and can now be used for verification.
  160. func (l *LightClientAttackEvidence) ValidateBasic() error {
  161. if l.ConflictingBlock == nil {
  162. return errors.New("conflicting block is nil")
  163. }
  164. // this check needs to be done before we can run validate basic
  165. if l.ConflictingBlock.Header == nil {
  166. return errors.New("conflicting block missing header")
  167. }
  168. if err := l.ConflictingBlock.ValidateBasic(l.ConflictingBlock.ChainID); err != nil {
  169. return fmt.Errorf("invalid conflicting light block: %w", err)
  170. }
  171. if l.CommonHeight <= 0 {
  172. return errors.New("negative or zero common height")
  173. }
  174. // check that common height isn't ahead of the height of the conflicting block. It
  175. // is possible that they are the same height if the light node witnesses either an
  176. // amnesia or a equivocation attack.
  177. if l.CommonHeight > l.ConflictingBlock.Height {
  178. return fmt.Errorf("common height is ahead of the conflicting block height (%d > %d)",
  179. l.CommonHeight, l.ConflictingBlock.Height)
  180. }
  181. return nil
  182. }
  183. // String returns a string representation of LightClientAttackEvidence
  184. func (l *LightClientAttackEvidence) String() string {
  185. return fmt.Sprintf("LightClientAttackEvidence{ConflictingBlock: %v, CommonHeight: %d}",
  186. l.ConflictingBlock.String(), l.CommonHeight)
  187. }
  188. // ToProto encodes LightClientAttackEvidence to protobuf
  189. func (l *LightClientAttackEvidence) ToProto() (*tmproto.LightClientAttackEvidence, error) {
  190. conflictingBlock, err := l.ConflictingBlock.ToProto()
  191. if err != nil {
  192. return nil, err
  193. }
  194. return &tmproto.LightClientAttackEvidence{
  195. ConflictingBlock: conflictingBlock,
  196. CommonHeight: l.CommonHeight,
  197. }, nil
  198. }
  199. // LightClientAttackEvidenceFromProto decodes protobuf
  200. func LightClientAttackEvidenceFromProto(l *tmproto.LightClientAttackEvidence) (*LightClientAttackEvidence, error) {
  201. if l == nil {
  202. return nil, errors.New("empty light client attack evidence")
  203. }
  204. conflictingBlock, err := LightBlockFromProto(l.ConflictingBlock)
  205. if err != nil {
  206. return nil, err
  207. }
  208. le := &LightClientAttackEvidence{
  209. ConflictingBlock: conflictingBlock,
  210. CommonHeight: l.CommonHeight,
  211. }
  212. return le, le.ValidateBasic()
  213. }
  214. //------------------------------------------------------------------------------------------
  215. // EvidenceList is a list of Evidence. Evidences is not a word.
  216. type EvidenceList []Evidence
  217. // Hash returns the simple merkle root hash of the EvidenceList.
  218. func (evl EvidenceList) Hash() []byte {
  219. // These allocations are required because Evidence is not of type Bytes, and
  220. // golang slices can't be typed cast. This shouldn't be a performance problem since
  221. // the Evidence size is capped.
  222. evidenceBzs := make([][]byte, len(evl))
  223. for i := 0; i < len(evl); i++ {
  224. evidenceBzs[i] = evl[i].Bytes()
  225. }
  226. return merkle.HashFromByteSlices(evidenceBzs)
  227. }
  228. func (evl EvidenceList) String() string {
  229. s := ""
  230. for _, e := range evl {
  231. s += fmt.Sprintf("%s\t\t", e)
  232. }
  233. return s
  234. }
  235. // Has returns true if the evidence is in the EvidenceList.
  236. func (evl EvidenceList) Has(evidence Evidence) bool {
  237. for _, ev := range evl {
  238. if bytes.Equal(evidence.Hash(), ev.Hash()) {
  239. return true
  240. }
  241. }
  242. return false
  243. }
  244. //------------------------------------------ PROTO --------------------------------------
  245. // EvidenceToProto is a generalized function for encoding evidence that conforms to the
  246. // evidence interface to protobuf
  247. func EvidenceToProto(evidence Evidence) (*tmproto.Evidence, error) {
  248. if evidence == nil {
  249. return nil, errors.New("nil evidence")
  250. }
  251. switch evi := evidence.(type) {
  252. case *DuplicateVoteEvidence:
  253. pbev := evi.ToProto()
  254. return &tmproto.Evidence{
  255. Sum: &tmproto.Evidence_DuplicateVoteEvidence{
  256. DuplicateVoteEvidence: pbev,
  257. },
  258. }, nil
  259. case *LightClientAttackEvidence:
  260. pbev, err := evi.ToProto()
  261. if err != nil {
  262. return nil, err
  263. }
  264. return &tmproto.Evidence{
  265. Sum: &tmproto.Evidence_LightClientAttackEvidence{
  266. LightClientAttackEvidence: pbev,
  267. },
  268. }, nil
  269. default:
  270. return nil, fmt.Errorf("toproto: evidence is not recognized: %T", evi)
  271. }
  272. }
  273. // EvidenceFromProto is a generalized function for decoding protobuf into the
  274. // evidence interface
  275. func EvidenceFromProto(evidence *tmproto.Evidence) (Evidence, error) {
  276. if evidence == nil {
  277. return nil, errors.New("nil evidence")
  278. }
  279. switch evi := evidence.Sum.(type) {
  280. case *tmproto.Evidence_DuplicateVoteEvidence:
  281. return DuplicateVoteEvidenceFromProto(evi.DuplicateVoteEvidence)
  282. case *tmproto.Evidence_LightClientAttackEvidence:
  283. return LightClientAttackEvidenceFromProto(evi.LightClientAttackEvidence)
  284. default:
  285. return nil, errors.New("evidence is not recognized")
  286. }
  287. }
  288. func init() {
  289. tmjson.RegisterType(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence")
  290. tmjson.RegisterType(&LightClientAttackEvidence{}, "tendermint/LightClientAttackEvidence")
  291. }
  292. //-------------------------------------------- ERRORS --------------------------------------
  293. // ErrInvalidEvidence wraps a piece of evidence and the error denoting how or why it is invalid.
  294. type ErrInvalidEvidence struct {
  295. Evidence Evidence
  296. Reason error
  297. }
  298. // NewErrInvalidEvidence returns a new EvidenceInvalid with the given err.
  299. func NewErrInvalidEvidence(ev Evidence, err error) *ErrInvalidEvidence {
  300. return &ErrInvalidEvidence{ev, err}
  301. }
  302. // Error returns a string representation of the error.
  303. func (err *ErrInvalidEvidence) Error() string {
  304. return fmt.Sprintf("Invalid evidence: %v. Evidence: %v", err.Reason, err.Evidence)
  305. }
  306. // ErrEvidenceOverflow is for when there the amount of evidence exceeds the max bytes.
  307. type ErrEvidenceOverflow struct {
  308. Max int64
  309. Got int64
  310. }
  311. // NewErrEvidenceOverflow returns a new ErrEvidenceOverflow where got > max.
  312. func NewErrEvidenceOverflow(max, got int64) *ErrEvidenceOverflow {
  313. return &ErrEvidenceOverflow{max, got}
  314. }
  315. // Error returns a string representation of the error.
  316. func (err *ErrEvidenceOverflow) Error() string {
  317. return fmt.Sprintf("Too much evidence: Max %d, got %d", err.Max, err.Got)
  318. }
  319. //-------------------------------------------- MOCKING --------------------------------------
  320. // unstable - use only for testing
  321. // assumes the round to be 0 and the validator index to be 0
  322. func NewMockDuplicateVoteEvidence(height int64, time time.Time, chainID string) *DuplicateVoteEvidence {
  323. val := NewMockPV()
  324. return NewMockDuplicateVoteEvidenceWithValidator(height, time, val, chainID)
  325. }
  326. func NewMockDuplicateVoteEvidenceWithValidator(height int64, time time.Time,
  327. pv PrivValidator, chainID string) *DuplicateVoteEvidence {
  328. pubKey, _ := pv.GetPubKey()
  329. voteA := makeMockVote(height, 0, 0, pubKey.Address(), randBlockID(), time)
  330. vA := voteA.ToProto()
  331. _ = pv.SignVote(chainID, vA)
  332. voteA.Signature = vA.Signature
  333. voteB := makeMockVote(height, 0, 0, pubKey.Address(), randBlockID(), time)
  334. vB := voteB.ToProto()
  335. _ = pv.SignVote(chainID, vB)
  336. voteB.Signature = vB.Signature
  337. return NewDuplicateVoteEvidence(voteA, voteB)
  338. }
  339. func makeMockVote(height int64, round, index int32, addr Address,
  340. blockID BlockID, time time.Time) *Vote {
  341. return &Vote{
  342. Type: tmproto.SignedMsgType(2),
  343. Height: height,
  344. Round: round,
  345. BlockID: blockID,
  346. Timestamp: time,
  347. ValidatorAddress: addr,
  348. ValidatorIndex: index,
  349. }
  350. }
  351. func randBlockID() BlockID {
  352. return BlockID{
  353. Hash: tmrand.Bytes(tmhash.Size),
  354. PartSetHeader: PartSetHeader{
  355. Total: 1,
  356. Hash: tmrand.Bytes(tmhash.Size),
  357. },
  358. }
  359. }