// blockParts: Must be parts of the block // seenValidation: The +2/3 precommits that were seen which committed at height. // If all the nodes restart after committing a block, // we need this to reload the precommits to catch-up nodes to the // most recent height. Otherwise they'd stall at H-1. func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenValidation *types.Validation) { height := block.Height if height != bs.height+1 { PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)) } if !blockParts.IsComplete() { PanicSanity(Fmt("BlockStore can only save complete block part sets")) } // Save block meta meta := types.NewBlockMeta(block, blockParts) metaBytes := wire.BinaryBytes(meta) bs.db.Set(calcBlockMetaKey(height), metaBytes) // Save block parts for i := 0; i < blockParts.Total(); i++ { bs.saveBlockPart(height, i, blockParts.GetPart(i)) } // Save block validation (duplicate and separate from the Block) blockValidationBytes := wire.BinaryBytes(block.LastValidation) bs.db.Set(calcBlockValidationKey(height-1), blockValidationBytes) // Save seen validation (seen +2/3 precommits for block) seenValidationBytes := wire.BinaryBytes(seenValidation) bs.db.Set(calcSeenValidationKey(height), seenValidationBytes) // Save new BlockStoreStateJSON descriptor BlockStoreStateJSON{Height: height}.Save(bs.db) // Done! bs.height = height }
// May block on send if queue is full. func (cs *ConsensusState) SetProposalAndBlock(proposal *types.Proposal, block *types.Block, parts *types.PartSet, peerKey string) error { cs.SetProposal(proposal, peerKey) for i := 0; i < parts.Total(); i++ { part := parts.GetPart(i) cs.AddProposalBlockPart(proposal.Height, proposal.Round, part, peerKey) } return nil // TODO errors }
func (cs *ConsensusState) decideProposal(height, round int) { var block *types.Block var blockParts *types.PartSet // Decide on block if cs.LockedBlock != nil { // If we're locked onto a block, just choose that. block, blockParts = cs.LockedBlock, cs.LockedBlockParts } else { // Create a new proposal block from state/txs from the mempool. block, blockParts = cs.createProposalBlock() if block == nil { // on error return } } // Make proposal proposal := types.NewProposal(height, round, blockParts.Header(), cs.Votes.POLRound()) err := cs.privValidator.SignProposal(cs.state.ChainID, proposal) if err == nil { // Set fields /* fields set by setProposal and addBlockPart cs.Proposal = proposal cs.ProposalBlock = block cs.ProposalBlockParts = blockParts */ // send proposal and block parts on internal msg queue cs.sendInternalMessage(msgInfo{&ProposalMessage{proposal}, ""}) for i := 0; i < blockParts.Total(); i++ { part := blockParts.GetPart(i) cs.sendInternalMessage(msgInfo{&BlockPartMessage{cs.Height, cs.Round, part}, ""}) } log.Info("Signed and sent proposal", "height", height, "round", round, "proposal", proposal) log.Debug(Fmt("Signed and sent proposal block: %v", block)) } else { log.Warn("enterPropose: Error signing proposal", "height", height, "round", round, "error", err) } }