// Save Block, save the +2/3 Commits we've seen, // and sign a Commit-Vote if we haven't already func (cs *ConsensusState) saveCommitVoteBlock(block *types.Block, blockParts *types.PartSet, commits *VoteSet) { // The proposal must be valid. if err := cs.stageBlock(block, blockParts); err != nil { // Prevent zombies. log.Warn("saveCommitVoteBlock() an invalid block", "error", err) return } // Save to blockStore. if cs.blockStore.Height() < block.Height { seenValidation := commits.MakeValidation() cs.blockStore.SaveBlock(block, blockParts, seenValidation) } // Save the state. cs.stagedState.Save() // Update mempool. cs.mempoolReactor.Mempool.ResetForBlockAndState(block, cs.stagedState) // Commit-vote if we haven't already. if cs.lastCommitVoteHeight < block.Height { cs.signAddVote(types.VoteTypeCommit, block.Hash(), blockParts.Header()) cs.lastCommitVoteHeight = block.Height } }
func (cs *ConsensusState) stageBlock(block *types.Block, blockParts *types.PartSet) error { if block == nil { panic("Cannot stage nil block") } // Already staged? blockHash := block.Hash() if cs.stagedBlock != nil && len(blockHash) != 0 && bytes.Equal(cs.stagedBlock.Hash(), blockHash) { return nil } // Create a copy of the state for staging stateCopy := cs.state.Copy() // reset the event cache and pass it into the state cs.evc = events.NewEventCache(cs.evsw) stateCopy.SetFireable(cs.evc) // Commit block onto the copied state. // NOTE: Basic validation is done in state.AppendBlock(). err := sm.ExecBlock(stateCopy, block, blockParts.Header()) if err != nil { return err } else { cs.stagedBlock = block cs.stagedState = stateCopy return nil } }
// sign a Commit-Vote func (cs *ConsensusState) commitVoteBlock(block *types.Block, blockParts *types.PartSet) { // The proposal must be valid. if err := cs.stageBlock(block, blockParts); err != nil { // Prevent zombies. log.Warn("commitVoteBlock() an invalid block", "error", err) return } // Commit-vote. if cs.lastCommitVoteHeight < block.Height { cs.signAddVote(types.VoteTypeCommit, block.Hash(), blockParts.Header()) cs.lastCommitVoteHeight = block.Height } else { log.Error("Duplicate commitVoteBlock() attempt", "lastCommitVoteHeight", cs.lastCommitVoteHeight, "types.Height", block.Height) } }
func (cs *ConsensusState) RunActionPropose(height uint, round uint) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || cs.Round != round { return } defer func() { cs.Step = RoundStepPropose cs.newStepCh <- cs.getRoundState() }() // Nothing to do if it's not our turn. if cs.privValidator == nil { return } if !bytes.Equal(cs.Validators.Proposer().Address, cs.privValidator.Address) { log.Debug("Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) return } else { log.Debug("Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) } var block *types.Block var blockParts *types.PartSet var pol *POL var polParts *types.PartSet // Decide on block and POL if cs.LockedBlock != nil { // If we're locked onto a block, just choose that. block = cs.LockedBlock blockParts = cs.LockedBlockParts pol = cs.LockedPOL } else { // Otherwise we should create a new proposal. var validation *types.Validation if cs.Height == 1 { // We're creating a proposal for the first block. // The validation is empty. validation = &types.Validation{} } else if cs.LastCommits.HasTwoThirdsMajority() { // Make the validation from LastCommits validation = cs.LastCommits.MakeValidation() } else { // Upon reboot, we may have to use SeenValidation validation = cs.blockStore.LoadSeenValidation(height - 1) if validation == nil { // We just don't have any validation for the previous block log.Debug("Cannot propose anything: No validation for the previous block.") return } } txs := cs.mempoolReactor.Mempool.GetProposalTxs() block = &types.Block{ Header: &types.Header{ Network: config.GetString("network"), Height: cs.Height, Time: time.Now(), Fees: 0, // TODO fees NumTxs: uint(len(txs)), LastBlockHash: cs.state.LastBlockHash, LastBlockParts: cs.state.LastBlockParts, StateHash: nil, // Will set afterwards. }, Validation: validation, Data: &types.Data{ Txs: txs, }, } // Set the types.Header.StateHash. err := cs.state.SetBlockStateHash(block) if err != nil { log.Error("Error setting state hash", "error", err) return } blockParts = block.MakePartSet() pol = cs.LockedPOL // If exists, is a PoUnlock. } if pol != nil { polParts = pol.MakePartSet() } // Make proposal proposal := NewProposal(cs.Height, cs.Round, blockParts.Header(), polParts.Header()) err := cs.privValidator.SignProposal(proposal) if err == nil { log.Info("Signed and set proposal", "height", cs.Height, "round", cs.Round, "proposal", proposal) log.Debug(Fmt("Signed and set proposal block: %v", block)) // Set fields cs.Proposal = proposal cs.ProposalBlock = block cs.ProposalBlockParts = blockParts cs.ProposalPOL = pol cs.ProposalPOLParts = polParts } else { log.Warn("Error signing proposal", "height", cs.Height, "round", cs.Round, "error", err) } }