Example #1
0
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
}
Example #2
0
// 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})
	}

}