dir : consensus/state.go
state, mempool의 tx를 이용해 새로운 block 생성 (이미 있다면 그걸 사용)
여기서 ValidBlock
이란, prevote 단계에서 2/3 이상의 동의를 받았으나 precommit을 충분히 받지 못해 lock 되어 저장된 이전 round의 block을 의미한다. 블럭 자체에는 문제가 없다는 사실이 이미 이전 round에서 확인되었으므로 계산을 다시 할 필요 없이 이를 재활용할 수 있다.
var block *types.Block
var blockparts *types.PartSet
if cs.ValidBlock != nil {
block, blockParts = cs.ValidBlock, cs.ValidBlockParts
} else {
block, blockParts = cs.createProposalBlock()
if block == nil {
return
}
}
flush WAL
flush 자체보다 flush 과정에서 기록이 제대로 저장되었는지 확인, 보증하는게 주된 목적이다.
if err := cs.wal.FlushAndSync(); err != nil {...}
make proposal (BlockID, types.Proposal 인스턴스)
propBlockID := types.BlockID{hash: block.hash(), partSetHeader : blockParts.Header()}
proposal := types.NewProposal(height, round, cs.ValidRound, propBlockID)
p := proposal.ToProto()
Proposal에 서명 추가
if err := cs.privValidator.SignProposal(cs.state.ChainID, p); err == nil {
// 인스턴스에 서명 값 입력
proposal.Signature = p.Signature
// internal msg 송신
cs.sendInternalMessage(msgInfo{&ProposalMessage{proposal}, ""})
// 모든 block parts들에 대해 internal msg 송신
for i := 0; i < int(blockParts.Total()); i++ {
part := blockparts.getpart(i)
// 이 internal msg를 handlemsg()에서 수신한다.
cs.sendInternalMessage(msgInfo{&BlockpartMessage{cs.Height, cs.Round, part}, ""})
}
} else if !cs.replayMode {
// ...
}