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