func (cs *ConsensusState) SetProposal(proposal *Proposal) error { cs.mtx.Lock() defer cs.mtx.Unlock() // Already have one if cs.Proposal != nil { return nil } // Does not apply if proposal.Height != cs.Height || proposal.Round != cs.Round { return nil } // We don't care about the proposal if we're already in RoundStepCommit. if cs.Step == RoundStepCommit { return nil } // Verify signature if !cs.Validators.Proposer().PubKey.VerifyBytes(account.SignBytes(proposal), proposal.Signature) { return ErrInvalidProposalSignature } cs.Proposal = proposal cs.ProposalBlockParts = types.NewPartSetFromHeader(proposal.BlockParts) cs.ProposalPOLParts = types.NewPartSetFromHeader(proposal.POLParts) return nil }
// Enter commit step. See the diagram for details. // There are two ways to enter this step: // * After the Precommit step with +2/3 precommits, or, // * Upon +2/3 commits regardless of current step // Either way this action is run at most once per round. func (cs *ConsensusState) RunActionCommit(height uint) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height { panic(Fmt("RunActionCommit(%v), expected %v", height, cs.Height)) } defer func() { cs.Step = RoundStepCommit cs.newStepCh <- cs.getRoundState() }() // Sanity check. // There are two ways to enter: // 1. +2/3 precommits at the end of RoundStepPrecommit // 2. +2/3 commits at any time hash, partsHeader, ok := cs.Precommits.TwoThirdsMajority() if !ok { hash, partsHeader, ok = cs.Commits.TwoThirdsMajority() if !ok { panic("RunActionCommit() expects +2/3 precommits or commits") } } // Clear the Locked* fields and use cs.Proposed* if cs.LockedBlock.HashesTo(hash) { cs.ProposalBlock = cs.LockedBlock cs.ProposalBlockParts = cs.LockedBlockParts cs.LockedBlock = nil cs.LockedBlockParts = nil cs.LockedPOL = nil } // If we don't have the block being committed, set up to get it. if !cs.ProposalBlock.HashesTo(hash) { if !cs.ProposalBlockParts.HasHeader(partsHeader) { // We're getting the wrong block. // Set up ProposalBlockParts and keep waiting. cs.ProposalBlock = nil cs.ProposalBlockParts = types.NewPartSetFromHeader(partsHeader) } else { // We just need to keep waiting. } } else { // We have the block, so sign a Commit-vote. cs.commitVoteBlock(cs.ProposalBlock, cs.ProposalBlockParts) } // If we have the block AND +2/3 commits, queue RoundActionTryFinalize. // Round will immediately become finalized. if cs.ProposalBlock.HashesTo(hash) && cs.Commits.HasTwoThirdsMajority() { cs.queueAction(RoundAction{cs.Height, cs.Round, RoundActionTryFinalize}) } }