CheckAndSetLastCertificate() validates the last quorum certificate included in the block and sets it in the ephemeral indexer NOTE: This must come before ApplyBlock in order to have the proposers 'lastCertificate' which is used for distributing rewards
(candidate *lib.BlockHeader)
| 584 | // CheckAndSetLastCertificate() validates the last quorum certificate included in the block and sets it in the ephemeral indexer |
| 585 | // NOTE: This must come before ApplyBlock in order to have the proposers 'lastCertificate' which is used for distributing rewards |
| 586 | func (c *Controller) CheckAndSetLastCertificate(candidate *lib.BlockHeader) lib.ErrorI { |
| 587 | if candidate.Height > 1 { |
| 588 | // load the last quorum certificate from state |
| 589 | lastCertificate, err := c.FSM.LoadCertificateHashesOnly(candidate.Height - 1) |
| 590 | // if an error occurred |
| 591 | if err != nil { |
| 592 | // exit with error |
| 593 | return err |
| 594 | } |
| 595 | // ensure the candidate 'last certificate' is for the same block and result as the expected |
| 596 | if !candidate.LastQuorumCertificate.EqualPayloads(lastCertificate) { |
| 597 | // exit with error |
| 598 | return lib.ErrInvalidLastQuorumCertificate() |
| 599 | } |
| 600 | // the synced blocks were already validated during consensus, no need to validate again |
| 601 | if !c.Syncing().Load() { |
| 602 | // define a convenience variable for the 'root height' |
| 603 | rHeight, height := candidate.LastQuorumCertificate.Header.RootHeight, candidate.LastQuorumCertificate.Header.Height |
| 604 | // get the committee from the 'root chain' from the n-1 height because state heights represent 'end block state' once committed |
| 605 | vs, err := c.LoadCommittee(c.LoadRootChainId(height), rHeight) // TODO investigate - during consensus it works without -1 but during syncing might need -1? |
| 606 | if err != nil { |
| 607 | // exit with error |
| 608 | return err |
| 609 | } |
| 610 | // ensure the last quorum certificate is valid |
| 611 | isPartialQC, err := candidate.LastQuorumCertificate.Check(vs, 0, &lib.View{ |
| 612 | Height: candidate.Height - 1, RootHeight: rHeight, NetworkId: c.Config.NetworkID, ChainId: c.Config.ChainId, |
| 613 | }, true) |
| 614 | // if the check failed |
| 615 | if err != nil { |
| 616 | // exit with error |
| 617 | return err |
| 618 | } |
| 619 | // ensure is a full +2/3rd maj QC |
| 620 | if isPartialQC { |
| 621 | return lib.ErrNoMaj23() |
| 622 | } |
| 623 | } |
| 624 | // update the LastQuorumCertificate in the ephemeral store to ensure deterministic last-COMMIT-QC (multiple valid versions can exist) |
| 625 | if err = c.FSM.Store().(lib.StoreI).IndexQC(candidate.LastQuorumCertificate); err != nil { |
| 626 | // exit with error |
| 627 | return err |
| 628 | } |
| 629 | } |
| 630 | // exit |
| 631 | return nil |
| 632 | } |
| 633 | |
| 634 | // SetFSMInConsensusModeForProposals() is how the Validator is configured for `base chain` specific parameter upgrades |
| 635 | func (c *Controller) SetFSMInConsensusModeForProposals() (reset func()) { |
no test coverage detected