代码位置:order/consensus/solo/consensus.go
Solo共识组件启动后执行chain.main方法,循环处理消息,同时将消息打包成block并提交给账本,代码结构非常简单,
处理流程如下:
func (ch *chain) main() {
//创建打包超时定时器
var timer <-chan time.Time
var err error
//循环接收消息
for {
//获取当前的配置序号
seq := ch.support.Sequence()
err = nil
select {
//接收Envelope消息
case msg := <-ch.sendChan:
//通过判断seq大小,判断当前消息是否为配置消息或者普通消息
if msg.configMsg == nil {
// NormalMsg,处理普通消息
if msg.configSeq < seq {
_, err = ch.support.ProcessNormalMsg(msg.normalMsg)
if err != nil {
logger.Warningf("Discarding bad normal message: %s", err)
continue
}
}
//调用(一)所讲解的blockcutter去打包数据,最多有2个batch的数据,当为2个batch时,
// 最后一个batch有且仅有一个message
batches, pending := ch.support.BlockCutter().Ordered(msg.normalMsg)
//循环写入Ledger中
for _, batch := range batches {
//创建区块
block := ch.support.CreateNextBlock(batch)
//将区块写入账本中
ch.support.WriteBlock(block, nil)
}
switch {
//当定时器不会空时,没有后续数据到来,停止定时器
case timer != nil && !pending:
// Timer is already running but there are no messages pending, stop the timer
timer = nil
//有数据,但定时器为空时,设置BatchTimeout为最大出快超时时间,超时该时间就会打包一个block
case timer == nil && pending:
// Timer is not already running and there are messages pending, so start it
timer = time.After(ch.support.SharedConfig().BatchTimeout())
logger.Debugf("Just began %s batch timer", ch.support.SharedConfig().BatchTimeout().String())
default:
// Do nothing when:
// 1. Timer is already running and there are messages pending
// 2. Timer is not set and there are no messages pending
}
} else {
// ConfigMsg,配置信息处理,和上述普通消息处理过程雷同
if msg.configSeq < seq {
msg.configMsg, _, err = ch.support.ProcessConfigMsg(msg.configMsg)
if err != nil {
logger.Warningf("Discarding bad config message: %s", err)
continue
}
}
batch := ch.support.BlockCutter().Cut()
if batch != nil {
block := ch.support.CreateNextBlock(batch)
ch.support.WriteBlock(block, nil)
}
block := ch.support.CreateNextBlock([]*cb.Envelope{msg.configMsg})
ch.support.WriteConfigBlock(block, nil)
timer = nil
}
//打包BatchTimeout超时定时器触发
case <-timer:
//clear the timer
timer = nil
//直接对缓存的message进行Cut打包
batch := ch.support.BlockCutter().Cut()
//如果batch为空,说明无消息可打包,继续等待消息
if len(batch) == 0 {
logger.Warningf("Batch timer expired with no pending requests, this might indicate a bug")
continue
}
//创建区块,写入账本
logger.Debugf("Batch timer expired, creating block")
block := ch.support.CreateNextBlock(batch)
ch.support.WriteBlock(block, nil)
//接收到exit chan时退出主逻辑
case <-ch.exitChan:
logger.Debugf("Exiting")
return
}
}