Пример #1
0
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)
	}
}