github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/evidence/pool.go (about) 1 package evidence 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 "github.com/gogo/protobuf/proto" 9 gogotypes "github.com/gogo/protobuf/types" 10 dbm "github.com/tendermint/tm-db" 11 12 clist "github.com/tendermint/tendermint/libs/clist" 13 "github.com/tendermint/tendermint/libs/log" 14 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 15 sm "github.com/tendermint/tendermint/state" 16 "github.com/tendermint/tendermint/store" 17 "github.com/tendermint/tendermint/types" 18 ) 19 20 const ( 21 baseKeyCommitted = byte(0x00) 22 baseKeyPending = byte(0x01) 23 baseKeyPOLC = byte(0x02) 24 baseKeyAwaitingTrial = byte(0x03) 25 ) 26 27 // Pool maintains a pool of valid evidence to be broadcasted and committed 28 type Pool struct { 29 logger log.Logger 30 31 evidenceStore dbm.DB 32 evidenceList *clist.CList // concurrent linked-list of evidence 33 34 // needed to load validators to verify evidence 35 stateDB dbm.DB 36 // needed to load headers to verify evidence 37 blockStore *store.BlockStore 38 39 mtx sync.Mutex 40 // latest state 41 state sm.State 42 // a map of active validators and respective last heights validator is active 43 // if it was in validator set after EvidenceParams.MaxAgeNumBlocks or 44 // currently is (ie. [MaxAgeNumBlocks, CurrentHeight]) 45 // In simple words, it means it's still bonded -> therefore slashable. 46 valToLastHeight valToLastHeightMap 47 48 nextEvidenceTrialEndedHeight int64 49 } 50 51 // Validator.Address -> Last height it was in validator set 52 type valToLastHeightMap map[string]int64 53 54 // Creates a new pool. If using an existing evidence store, it will add all pending evidence 55 // to the concurrent list. 56 func NewPool(stateDB, evidenceDB dbm.DB, blockStore *store.BlockStore) (*Pool, error) { 57 var ( 58 state = sm.LoadState(stateDB) 59 ) 60 61 valToLastHeight, err := buildValToLastHeightMap(state, stateDB, blockStore) 62 if err != nil { 63 return nil, err 64 } 65 66 pool := &Pool{ 67 stateDB: stateDB, 68 blockStore: blockStore, 69 state: state, 70 logger: log.NewNopLogger(), 71 evidenceStore: evidenceDB, 72 evidenceList: clist.New(), 73 valToLastHeight: valToLastHeight, 74 nextEvidenceTrialEndedHeight: -1, 75 } 76 77 // if pending evidence already in db, in event of prior failure, then load it back to the evidenceList 78 evList := pool.AllPendingEvidence() 79 for _, ev := range evList { 80 pool.evidenceList.PushBack(ev) 81 } 82 83 return pool, nil 84 } 85 86 // PendingEvidence is used primarily as part of block proposal and returns up to maxNum of uncommitted evidence. 87 // If maxNum is -1, all evidence is returned. Pending evidence is prioritized based on time. 88 func (evpool *Pool) PendingEvidence(maxNum uint32) []types.Evidence { 89 evpool.removeExpiredPendingEvidence() 90 evidence, err := evpool.listEvidence(baseKeyPending, int64(maxNum)) 91 if err != nil { 92 evpool.logger.Error("Unable to retrieve pending evidence", "err", err) 93 } 94 return evidence 95 } 96 97 // AllPendingEvidence returns all evidence ready to be proposed and committed. 98 func (evpool *Pool) AllPendingEvidence() []types.Evidence { 99 evpool.removeExpiredPendingEvidence() 100 evidence, err := evpool.listEvidence(baseKeyPending, -1) 101 if err != nil { 102 evpool.logger.Error("Unable to retrieve pending evidence", "err", err) 103 } 104 return evidence 105 } 106 107 // Update uses the latest block & state to update its copy of the state, 108 // validator to last height map and calls MarkEvidenceAsCommitted. 109 func (evpool *Pool) Update(block *types.Block, state sm.State) { 110 // sanity check 111 if state.LastBlockHeight != block.Height { 112 panic(fmt.Sprintf("Failed EvidencePool.Update sanity check: got state.Height=%d with block.Height=%d", 113 state.LastBlockHeight, 114 block.Height, 115 ), 116 ) 117 } 118 119 // update the state 120 evpool.updateState(state) 121 122 // remove evidence from pending and mark committed 123 evpool.MarkEvidenceAsCommitted(block.Height, block.Evidence.Evidence) 124 125 // prune pending, committed and potential evidence and polc's periodically 126 if block.Height%state.ConsensusParams.Evidence.MaxAgeNumBlocks == 0 { 127 evpool.logger.Debug("Pruning no longer necessary evidence") 128 evpool.pruneExpiredPOLC() 129 evpool.removeExpiredPendingEvidence() 130 } 131 132 evpool.updateValToLastHeight(block.Height, state) 133 134 if evpool.nextEvidenceTrialEndedHeight > 0 && block.Height > evpool.nextEvidenceTrialEndedHeight { 135 evpool.logger.Debug("Upgrading all potential evidence that have served the trial period") 136 evpool.nextEvidenceTrialEndedHeight = evpool.upgradePotentialAmnesiaEvidence() 137 } 138 } 139 140 // AddPOLC adds a proof of lock change to the evidence database 141 // that may be needed in the future to verify votes 142 func (evpool *Pool) AddPOLC(polc *types.ProofOfLockChange) error { 143 key := keyPOLC(polc) 144 pbplc, err := polc.ToProto() 145 if err != nil { 146 return err 147 } 148 polcBytes, err := proto.Marshal(pbplc) 149 if err != nil { 150 return fmt.Errorf("addPOLC: unable to marshal ProofOfLockChange: %w", err) 151 } 152 return evpool.evidenceStore.Set(key, polcBytes) 153 } 154 155 // AddEvidence checks the evidence is valid and adds it to the pool. If 156 // evidence is composite (ConflictingHeadersEvidence), it will be broken up 157 // into smaller pieces. 158 func (evpool *Pool) AddEvidence(evidence types.Evidence) error { 159 var ( 160 state = evpool.State() 161 evList = []types.Evidence{evidence} 162 ) 163 164 evpool.logger.Debug("Attempting to add evidence", "ev", evidence) 165 166 valSet, err := sm.LoadValidators(evpool.stateDB, evidence.Height()) 167 if err != nil { 168 return fmt.Errorf("can't load validators at height #%d: %w", evidence.Height(), err) 169 } 170 171 // Break composite evidence into smaller pieces. 172 if ce, ok := evidence.(types.CompositeEvidence); ok { 173 evpool.logger.Info("Breaking up composite evidence", "ev", evidence) 174 175 blockMeta := evpool.blockStore.LoadBlockMeta(evidence.Height()) 176 if blockMeta == nil { 177 return fmt.Errorf("don't have block meta at height #%d", evidence.Height()) 178 } 179 180 if err := ce.VerifyComposite(&blockMeta.Header, valSet); err != nil { 181 return err 182 } 183 184 // XXX: Copy here since this should be a rare case. 185 evpool.mtx.Lock() 186 valToLastHeightCopy := make(valToLastHeightMap, len(evpool.valToLastHeight)) 187 for k, v := range evpool.valToLastHeight { 188 valToLastHeightCopy[k] = v 189 } 190 evpool.mtx.Unlock() 191 192 evList = ce.Split(&blockMeta.Header, valSet, valToLastHeightCopy) 193 } 194 195 for _, ev := range evList { 196 197 if evpool.Has(ev) { 198 // if it is an amnesia evidence we have but POLC is not absent then 199 // we should still process it 200 if ae, ok := ev.(*types.AmnesiaEvidence); !ok || ae.Polc.IsAbsent() { 201 continue 202 } 203 } 204 205 // For lunatic validator evidence, a header needs to be fetched. 206 var header *types.Header 207 if _, ok := ev.(*types.LunaticValidatorEvidence); ok { 208 header = evpool.Header(ev.Height()) 209 if header == nil { 210 return fmt.Errorf("don't have block meta at height #%d", ev.Height()) 211 } 212 } 213 214 // 1) Verify against state. 215 if err := sm.VerifyEvidence(evpool.stateDB, state, ev, header); err != nil { 216 return fmt.Errorf("failed to verify %v: %w", ev, err) 217 } 218 219 // For potential amnesia evidence, if this node is indicted it shall retrieve a polc 220 // to form AmensiaEvidence else start the trial period for the piece of evidence 221 if pe, ok := ev.(*types.PotentialAmnesiaEvidence); ok { 222 if err := evpool.handleInboundPotentialAmnesiaEvidence(pe); err != nil { 223 return err 224 } 225 continue 226 } else if ae, ok := ev.(*types.AmnesiaEvidence); ok { 227 if ae.Polc.IsAbsent() && ae.PotentialAmnesiaEvidence.VoteA.Round < 228 ae.PotentialAmnesiaEvidence.VoteB.Round { 229 if err := evpool.handleInboundPotentialAmnesiaEvidence(ae.PotentialAmnesiaEvidence); err != nil { 230 return fmt.Errorf("failed to handle amnesia evidence, err: %w", err) 231 } 232 continue 233 } else { 234 // we are going to add this amnesia evidence and check if we already have an amnesia evidence or potential 235 // amnesia evidence that addesses the same case 236 aeWithoutPolc := types.NewAmnesiaEvidence(ae.PotentialAmnesiaEvidence, types.NewEmptyPOLC()) 237 if evpool.IsPending(aeWithoutPolc) { 238 evpool.removePendingEvidence(aeWithoutPolc) 239 } else if evpool.IsOnTrial(ae.PotentialAmnesiaEvidence) { 240 key := keyAwaitingTrial(ae.PotentialAmnesiaEvidence) 241 if err := evpool.evidenceStore.Delete(key); err != nil { 242 evpool.logger.Error("Failed to remove potential amnesia evidence from database", "err", err) 243 } 244 } 245 } 246 } 247 248 // 2) Save to store. 249 if err := evpool.addPendingEvidence(ev); err != nil { 250 return fmt.Errorf("database error when adding evidence: %v", err) 251 } 252 253 // 3) Add evidence to clist. 254 evpool.evidenceList.PushBack(ev) 255 256 evpool.logger.Info("Verified new evidence of byzantine behaviour", "evidence", ev) 257 } 258 259 return nil 260 } 261 262 // MarkEvidenceAsCommitted marks all the evidence as committed and removes it 263 // from the queue. 264 func (evpool *Pool) MarkEvidenceAsCommitted(height int64, evidence []types.Evidence) { 265 // make a map of committed evidence to remove from the clist 266 blockEvidenceMap := make(map[string]struct{}) 267 for _, ev := range evidence { 268 // As the evidence is stored in the block store we only need to record the height that it was saved at. 269 key := keyCommitted(ev) 270 271 h := gogotypes.Int64Value{Value: height} 272 evBytes, err := proto.Marshal(&h) 273 if err != nil { 274 panic(err) 275 } 276 277 if err := evpool.evidenceStore.Set(key, evBytes); err != nil { 278 evpool.logger.Error("Unable to add committed evidence", "err", err) 279 // if we can't move evidence to committed then don't remove the evidence from pending 280 continue 281 } 282 // if pending, remove from that bucket, remember not all evidence has been seen before 283 if evpool.IsPending(ev) { 284 evpool.removePendingEvidence(ev) 285 blockEvidenceMap[evMapKey(ev)] = struct{}{} 286 } 287 } 288 289 // remove committed evidence from the clist 290 if len(blockEvidenceMap) != 0 { 291 evpool.removeEvidenceFromList(blockEvidenceMap) 292 } 293 } 294 295 // Has checks whether the evidence exists either pending or already committed 296 func (evpool *Pool) Has(evidence types.Evidence) bool { 297 return evpool.IsPending(evidence) || evpool.IsCommitted(evidence) || evpool.IsOnTrial(evidence) 298 } 299 300 // IsEvidenceExpired checks whether evidence is past the maximum age where it can be used 301 func (evpool *Pool) IsEvidenceExpired(evidence types.Evidence) bool { 302 return evpool.IsExpired(evidence.Height(), evidence.Time()) 303 } 304 305 // IsExpired checks whether evidence or a polc is expired by checking whether a height and time is older 306 // than set by the evidence consensus parameters 307 func (evpool *Pool) IsExpired(height int64, time time.Time) bool { 308 var ( 309 params = evpool.State().ConsensusParams.Evidence 310 ageDuration = evpool.State().LastBlockTime.Sub(time) 311 ageNumBlocks = evpool.State().LastBlockHeight - height 312 ) 313 return ageNumBlocks > params.MaxAgeNumBlocks && 314 ageDuration > params.MaxAgeDuration 315 } 316 317 // IsCommitted returns true if we have already seen this exact evidence and it is already marked as committed. 318 func (evpool *Pool) IsCommitted(evidence types.Evidence) bool { 319 key := keyCommitted(evidence) 320 ok, err := evpool.evidenceStore.Has(key) 321 if err != nil { 322 evpool.logger.Error("Unable to find committed evidence", "err", err) 323 } 324 return ok 325 } 326 327 // IsPending checks whether the evidence is already pending. DB errors are passed to the logger. 328 func (evpool *Pool) IsPending(evidence types.Evidence) bool { 329 key := keyPending(evidence) 330 ok, err := evpool.evidenceStore.Has(key) 331 if err != nil { 332 evpool.logger.Error("Unable to find pending evidence", "err", err) 333 } 334 return ok 335 } 336 337 // IsOnTrial checks whether a piece of evidence is in the awaiting bucket. 338 // Only Potential Amnesia Evidence is stored here. 339 func (evpool *Pool) IsOnTrial(evidence types.Evidence) bool { 340 pe, ok := evidence.(*types.PotentialAmnesiaEvidence) 341 342 if !ok { 343 return false 344 } 345 346 key := keyAwaitingTrial(pe) 347 ok, err := evpool.evidenceStore.Has(key) 348 if err != nil { 349 evpool.logger.Error("Unable to find evidence on trial", "err", err) 350 } 351 return ok 352 } 353 354 // RetrievePOLC attempts to find a polc at the given height and round, if not there than exist returns false, all 355 // database errors are automatically logged 356 func (evpool *Pool) RetrievePOLC(height int64, round int32) (*types.ProofOfLockChange, error) { 357 var pbpolc tmproto.ProofOfLockChange 358 key := keyPOLCFromHeightAndRound(height, round) 359 polcBytes, err := evpool.evidenceStore.Get(key) 360 if err != nil { 361 evpool.logger.Error("Unable to retrieve polc", "err", err) 362 return nil, err 363 } 364 365 // polc doesn't exist 366 if polcBytes == nil { 367 return nil, nil 368 } 369 370 err = proto.Unmarshal(polcBytes, &pbpolc) 371 if err != nil { 372 return nil, err 373 } 374 polc, err := types.ProofOfLockChangeFromProto(&pbpolc) 375 if err != nil { 376 return nil, err 377 } 378 379 return polc, err 380 } 381 382 // EvidenceFront goes to the first evidence in the clist 383 func (evpool *Pool) EvidenceFront() *clist.CElement { 384 return evpool.evidenceList.Front() 385 } 386 387 // EvidenceWaitChan is a channel that closes once the first evidence in the list is there. i.e Front is not nil 388 func (evpool *Pool) EvidenceWaitChan() <-chan struct{} { 389 return evpool.evidenceList.WaitChan() 390 } 391 392 // SetLogger sets the Logger. 393 func (evpool *Pool) SetLogger(l log.Logger) { 394 evpool.logger = l 395 } 396 397 // Header gets the header from the block store at a specified height. 398 // Is used for validation of LunaticValidatorEvidence 399 func (evpool *Pool) Header(height int64) *types.Header { 400 blockMeta := evpool.blockStore.LoadBlockMeta(height) 401 if blockMeta == nil { 402 return nil 403 } 404 return &blockMeta.Header 405 } 406 407 // ValidatorLastHeight returns the last height of the validator w/ the 408 // given address. 0 - if address never was a validator or was such a 409 // long time ago (> ConsensusParams.Evidence.MaxAgeDuration && > 410 // ConsensusParams.Evidence.MaxAgeNumBlocks). 411 func (evpool *Pool) ValidatorLastHeight(address []byte) int64 { 412 evpool.mtx.Lock() 413 defer evpool.mtx.Unlock() 414 415 h, ok := evpool.valToLastHeight[string(address)] 416 if !ok { 417 return 0 418 } 419 return h 420 } 421 422 // State returns the current state of the evpool. 423 func (evpool *Pool) State() sm.State { 424 evpool.mtx.Lock() 425 defer evpool.mtx.Unlock() 426 return evpool.state 427 } 428 429 func (evpool *Pool) addPendingEvidence(evidence types.Evidence) error { 430 evi, err := types.EvidenceToProto(evidence) 431 if err != nil { 432 return fmt.Errorf("unable to convert to proto, err: %w", err) 433 } 434 435 evBytes, err := proto.Marshal(evi) 436 if err != nil { 437 return fmt.Errorf("unable to marshal evidence: %w", err) 438 } 439 440 key := keyPending(evidence) 441 442 return evpool.evidenceStore.Set(key, evBytes) 443 } 444 445 func (evpool *Pool) removePendingEvidence(evidence types.Evidence) { 446 key := keyPending(evidence) 447 if err := evpool.evidenceStore.Delete(key); err != nil { 448 evpool.logger.Error("Unable to delete pending evidence", "err", err) 449 } else { 450 evpool.logger.Info("Deleted pending evidence", "evidence", evidence) 451 } 452 } 453 454 // listEvidence lists up to maxNum pieces of evidence for the given prefix key. 455 // If maxNum is -1, there's no cap on the size of returned evidence. 456 func (evpool *Pool) listEvidence(prefixKey byte, maxNum int64) ([]types.Evidence, error) { 457 var count int64 458 var evidence []types.Evidence 459 iter, err := dbm.IteratePrefix(evpool.evidenceStore, []byte{prefixKey}) 460 if err != nil { 461 return nil, fmt.Errorf("database error: %v", err) 462 } 463 defer iter.Close() 464 for ; iter.Valid(); iter.Next() { 465 if count == maxNum { 466 return evidence, nil 467 } 468 count++ 469 470 val := iter.Value() 471 var ( 472 ev types.Evidence 473 evpb tmproto.Evidence 474 ) 475 err := proto.Unmarshal(val, &evpb) 476 if err != nil { 477 return nil, err 478 } 479 480 ev, err = types.EvidenceFromProto(&evpb) 481 if err != nil { 482 return nil, err 483 } 484 485 evidence = append(evidence, ev) 486 } 487 488 return evidence, nil 489 } 490 491 func (evpool *Pool) removeExpiredPendingEvidence() { 492 iter, err := dbm.IteratePrefix(evpool.evidenceStore, []byte{baseKeyPending}) 493 if err != nil { 494 evpool.logger.Error("Unable to iterate over pending evidence", "err", err) 495 return 496 } 497 defer iter.Close() 498 blockEvidenceMap := make(map[string]struct{}) 499 for ; iter.Valid(); iter.Next() { 500 evBytes := iter.Value() 501 var ( 502 ev types.Evidence 503 evpb tmproto.Evidence 504 ) 505 err := proto.Unmarshal(evBytes, &evpb) 506 if err != nil { 507 evpool.logger.Error("Unable to unmarshal Evidence", "err", err) 508 continue 509 } 510 511 ev, err = types.EvidenceFromProto(&evpb) 512 if err != nil { 513 evpool.logger.Error("Error in transition evidence from protobuf", "err", err) 514 continue 515 } 516 if !evpool.IsExpired(ev.Height()-1, ev.Time()) { 517 if len(blockEvidenceMap) != 0 { 518 evpool.removeEvidenceFromList(blockEvidenceMap) 519 } 520 521 return 522 } 523 evpool.removePendingEvidence(ev) 524 blockEvidenceMap[evMapKey(ev)] = struct{}{} 525 } 526 } 527 528 func (evpool *Pool) removeEvidenceFromList( 529 blockEvidenceMap map[string]struct{}) { 530 531 for e := evpool.evidenceList.Front(); e != nil; e = e.Next() { 532 // Remove from clist 533 ev := e.Value.(types.Evidence) 534 if _, ok := blockEvidenceMap[evMapKey(ev)]; ok { 535 evpool.evidenceList.Remove(e) 536 e.DetachPrev() 537 } 538 } 539 } 540 541 func (evpool *Pool) pruneExpiredPOLC() { 542 evpool.logger.Debug("Pruning expired POLC's") 543 iter, err := dbm.IteratePrefix(evpool.evidenceStore, []byte{baseKeyPOLC}) 544 if err != nil { 545 evpool.logger.Error("Unable to iterate over POLC's", "err", err) 546 return 547 } 548 defer iter.Close() 549 for ; iter.Valid(); iter.Next() { 550 proofBytes := iter.Value() 551 var ( 552 pbproof tmproto.ProofOfLockChange 553 ) 554 err := proto.Unmarshal(proofBytes, &pbproof) 555 if err != nil { 556 evpool.logger.Error("Unable to unmarshal POLC", "err", err) 557 continue 558 } 559 proof, err := types.ProofOfLockChangeFromProto(&pbproof) 560 if err != nil { 561 evpool.logger.Error("Unable to transition POLC from protobuf", "err", err) 562 continue 563 } 564 if !evpool.IsExpired(proof.Height()-1, proof.Time()) { 565 return 566 } 567 err = evpool.evidenceStore.Delete(iter.Key()) 568 if err != nil { 569 evpool.logger.Error("Unable to delete expired POLC", "err", err) 570 continue 571 } 572 evpool.logger.Info("Deleted expired POLC", "polc", proof) 573 } 574 } 575 576 func (evpool *Pool) updateState(state sm.State) { 577 evpool.mtx.Lock() 578 defer evpool.mtx.Unlock() 579 evpool.state = state 580 } 581 582 // upgrades any potential evidence that has undergone the trial period and is primed to be made into 583 // amnesia evidence 584 func (evpool *Pool) upgradePotentialAmnesiaEvidence() int64 { 585 iter, err := dbm.IteratePrefix(evpool.evidenceStore, []byte{baseKeyAwaitingTrial}) 586 if err != nil { 587 evpool.logger.Error("Unable to iterate over POLC's", "err", err) 588 return -1 589 } 590 defer iter.Close() 591 trialPeriod := evpool.State().ConsensusParams.Evidence.ProofTrialPeriod 592 currentHeight := evpool.State().LastBlockHeight 593 // 1) Iterate through all potential amnesia evidence in order of height 594 for ; iter.Valid(); iter.Next() { 595 paeBytes := iter.Value() 596 // 2) Retrieve the evidence 597 var evpb tmproto.Evidence 598 err := evpb.Unmarshal(paeBytes) 599 if err != nil { 600 evpool.logger.Error("Unable to unmarshal potential amnesia evidence", "err", err) 601 continue 602 } 603 ev, err := types.EvidenceFromProto(&evpb) 604 if err != nil { 605 evpool.logger.Error("Converting from proto to evidence", "err", err) 606 continue 607 } 608 // 3) Check if the trial period has lapsed and amnesia evidence can be formed 609 if pe, ok := ev.(*types.PotentialAmnesiaEvidence); ok { 610 if pe.Primed(trialPeriod, currentHeight) { 611 ae := types.NewAmnesiaEvidence(pe, types.NewEmptyPOLC()) 612 err := evpool.addPendingEvidence(ae) 613 if err != nil { 614 evpool.logger.Error("Unable to add amnesia evidence", "err", err) 615 continue 616 } 617 evpool.logger.Info("Upgraded to amnesia evidence", "amnesiaEvidence", ae) 618 err = evpool.evidenceStore.Delete(iter.Key()) 619 if err != nil { 620 evpool.logger.Error("Unable to delete potential amnesia evidence", "err", err) 621 continue 622 } 623 } else { 624 evpool.logger.Debug("Potential amnesia evidence is not ready to be upgraded. Ready at", "height", 625 pe.HeightStamp+trialPeriod, "currentHeight", currentHeight) 626 // once we reach a piece of evidence that isn't ready send back the height with which it will be ready 627 return pe.HeightStamp + trialPeriod 628 } 629 } 630 } 631 // if we have no evidence left to process we want to reset nextEvidenceTrialEndedHeight 632 return -1 633 } 634 635 func (evpool *Pool) handleInboundPotentialAmnesiaEvidence(pe *types.PotentialAmnesiaEvidence) error { 636 var ( 637 height = pe.Height() 638 exists = false 639 polc *types.ProofOfLockChange 640 err error 641 ) 642 643 evpool.logger.Debug("Received Potential Amnesia Evidence", "pe", pe) 644 645 // a) first try to find a corresponding polc 646 for round := pe.VoteB.Round; round > pe.VoteA.Round; round-- { 647 polc, err = evpool.RetrievePOLC(height, round) 648 if err != nil { 649 evpool.logger.Error("Failed to retrieve polc for potential amnesia evidence", "err", err, "pae", pe.String()) 650 continue 651 } 652 if polc != nil && !polc.IsAbsent() { 653 evpool.logger.Debug("Found polc for potential amnesia evidence", "polc", polc) 654 // we should not need to verify it if both the polc and potential amnesia evidence have already 655 // been verified. We replace the potential amnesia evidence. 656 ae := types.NewAmnesiaEvidence(pe, polc) 657 err := evpool.AddEvidence(ae) 658 if err != nil { 659 evpool.logger.Error("Failed to create amnesia evidence from potential amnesia evidence", "err", err) 660 // revert back to processing potential amnesia evidence 661 exists = false 662 } else { 663 evpool.logger.Info("Formed amnesia evidence from own polc", "amnesiaEvidence", ae) 664 } 665 break 666 } 667 } 668 669 // stamp height that the evidence was received 670 pe.HeightStamp = evpool.State().LastBlockHeight 671 672 // b) check if amnesia evidence can be made now or if we need to enact the trial period 673 if !exists && pe.Primed(1, pe.HeightStamp) { 674 evpool.logger.Debug("PotentialAmnesiaEvidence can be instantly upgraded") 675 err := evpool.AddEvidence(types.NewAmnesiaEvidence(pe, types.NewEmptyPOLC())) 676 if err != nil { 677 return err 678 } 679 } else if !exists && evpool.State().LastBlockHeight+evpool.State().ConsensusParams.Evidence.ProofTrialPeriod < 680 pe.Height()+evpool.State().ConsensusParams.Evidence.MaxAgeNumBlocks { 681 // if we can't find a proof of lock change and we know that the trial period will finish before the 682 // evidence has expired, then we commence the trial period by saving it in the awaiting bucket 683 pbe, err := types.EvidenceToProto(pe) 684 if err != nil { 685 return err 686 } 687 evBytes, err := pbe.Marshal() 688 if err != nil { 689 return err 690 } 691 key := keyAwaitingTrial(pe) 692 err = evpool.evidenceStore.Set(key, evBytes) 693 if err != nil { 694 return err 695 } 696 evpool.logger.Debug("Valid potential amnesia evidence has been added. Starting trial period", 697 "ev", pe) 698 // keep track of when the next pe has finished the trial period 699 if evpool.nextEvidenceTrialEndedHeight == -1 { 700 evpool.nextEvidenceTrialEndedHeight = pe.Height() + evpool.State().ConsensusParams.Evidence.ProofTrialPeriod 701 } 702 703 // add to the broadcast list so it can continue to be gossiped 704 evpool.evidenceList.PushBack(pe) 705 } 706 707 return nil 708 } 709 710 func evMapKey(ev types.Evidence) string { 711 return string(ev.Hash()) 712 } 713 714 func (evpool *Pool) updateValToLastHeight(blockHeight int64, state sm.State) { 715 evpool.mtx.Lock() 716 defer evpool.mtx.Unlock() 717 718 // Update current validators & add new ones. 719 for _, val := range state.Validators.Validators { 720 evpool.valToLastHeight[string(val.Address)] = blockHeight 721 } 722 723 // Remove validators outside of MaxAgeNumBlocks & MaxAgeDuration. 724 removeHeight := blockHeight - state.ConsensusParams.Evidence.MaxAgeNumBlocks 725 if removeHeight >= 1 { 726 for val, height := range evpool.valToLastHeight { 727 if height <= removeHeight { 728 delete(evpool.valToLastHeight, val) 729 } 730 } 731 } 732 } 733 734 func buildValToLastHeightMap(state sm.State, stateDB dbm.DB, blockStore *store.BlockStore) (valToLastHeightMap, error) { 735 var ( 736 valToLastHeight = make(map[string]int64) 737 params = state.ConsensusParams.Evidence 738 739 numBlocks = int64(0) 740 minAgeTime = time.Now().Add(-params.MaxAgeDuration) 741 height = state.LastBlockHeight 742 ) 743 744 if height == 0 { 745 return valToLastHeight, nil 746 } 747 748 meta := blockStore.LoadBlockMeta(height) 749 if meta == nil { 750 return nil, fmt.Errorf("block meta for height %d not found", height) 751 } 752 blockTime := meta.Header.Time 753 754 // From state.LastBlockHeight, build a map of "active" validators until 755 // MaxAgeNumBlocks is passed and block time is less than now() - 756 // MaxAgeDuration. 757 for height >= 1 && (numBlocks <= params.MaxAgeNumBlocks || !blockTime.Before(minAgeTime)) { 758 valSet, err := sm.LoadValidators(stateDB, height) 759 if err != nil { 760 // last stored height -> return 761 if _, ok := err.(sm.ErrNoValSetForHeight); ok { 762 return valToLastHeight, nil 763 } 764 return nil, fmt.Errorf("validator set for height %d not found", height) 765 } 766 767 for _, val := range valSet.Validators { 768 key := string(val.Address) 769 if _, ok := valToLastHeight[key]; !ok { 770 valToLastHeight[key] = height 771 } 772 } 773 774 height-- 775 776 if height > 0 { 777 // NOTE: we assume here blockStore and state.Validators are in sync. I.e if 778 // block N is stored, then validators for height N are also stored in 779 // state. 780 meta := blockStore.LoadBlockMeta(height) 781 if meta == nil { 782 return nil, fmt.Errorf("block meta for height %d not found", height) 783 } 784 blockTime = meta.Header.Time 785 } 786 787 numBlocks++ 788 } 789 790 return valToLastHeight, nil 791 } 792 793 // big endian padded hex 794 func bE(h int64) string { 795 return fmt.Sprintf("%0.16X", h) 796 } 797 798 func keyCommitted(evidence types.Evidence) []byte { 799 return append([]byte{baseKeyCommitted}, keySuffix(evidence)...) 800 } 801 802 func keyPending(evidence types.Evidence) []byte { 803 return append([]byte{baseKeyPending}, keySuffix(evidence)...) 804 } 805 806 func keyAwaitingTrial(evidence types.Evidence) []byte { 807 return append([]byte{baseKeyAwaitingTrial}, keySuffix(evidence)...) 808 } 809 810 func keyPOLC(polc *types.ProofOfLockChange) []byte { 811 return keyPOLCFromHeightAndRound(polc.Height(), polc.Round()) 812 } 813 814 func keyPOLCFromHeightAndRound(height int64, round int32) []byte { 815 return append([]byte{baseKeyPOLC}, []byte(fmt.Sprintf("%s/%s", bE(height), bE(int64(round))))...) 816 } 817 818 func keySuffix(evidence types.Evidence) []byte { 819 return []byte(fmt.Sprintf("%s/%X", bE(evidence.Height()), evidence.Hash())) 820 } 821 822 // ErrInvalidEvidence returns when evidence failed to validate 823 type ErrInvalidEvidence struct { 824 Reason error 825 } 826 827 func (e ErrInvalidEvidence) Error() string { 828 return fmt.Sprintf("evidence is not valid: %v ", e.Reason) 829 }