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) } }