fabric1.0学习笔记(1)
fabric1.0学习笔记(2)
fabric1.0学习笔记(3)
fabric1.0学习笔记(4)
fabric1.0学习笔记(5)
fabric1.0学习笔记(6)
在 fabric1.0学习笔记(2)中对main函数中用到的manager包进行了了解,它就像一个管家,管理了orderer节点涉及的链(也可以说是通道)、共识机制、账本对象及创建链方法、对账本的操作方法等。其中用到了一个chainsupport对象,它就像是一条链的管家,管理一条链上信息,主要是账本资源及区块处理方法(过滤器、区块切割器)等,下面是对chainsupport的解析
- ChainSupport包
// ConsenterSupport provides the resources available to a Consenter implementation
type ConsenterSupport interface {
crypto.LocalSigner // 签名
BlockCutter() blockcutter.Receiver //区块切割对象
SharedConfig() config.Orderer //orderer相关配置
CreateNextBlock(messages []*cb.Envelope) *cb.Block //把切割好的交易打包成区块
WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block //将区块写入临时区块
ChainID() string // ChainID returns the chain ID this specific consenter instance is associated with //链(channel)的ID
Height() uint64 // Returns the number of blocks on the chain this specific consenter instance is associated with //区块高度
}
// ChainSupport provides a wrapper for the resources backing a chain
type ChainSupport interface {
// This interface is actually the union with the deliver.Support but because of a golang
// limitation https://github.com/golang/go/issues/6977 the methods must be explicitly declared
// PolicyManager returns the current policy manager as specified by the chain config
'读取背书策略(返回当前的policy manager(策略管理器))'
PolicyManager() policies.Manager
// Reader returns the chain Reader for the chain
'读取账本的对象接口(返回链的Reader(账本的操作对象))'
Reader() ledger.Reader
// Errored returns whether the backing consenter has errored
'返回账本的处理过程是否有错误(返回打包的共识机制是否正确)'
Errored() <-chan struct{}
broadcast.Support '处理交易输入(返回广播所用的辅助资源)'
ConsenterSupport '共识机制的帮助方法(返回共识机制实现所需要的资源)'
// Sequence returns the current config sequence number
'每次更新配置都会加一(返回当前配置序列号)'
Sequence() uint64
// ProposeConfigUpdate applies a CONFIG_UPDATE to an existing config to produce a *cb.ConfigEnvelope
'将一个交易转换为配置交易(更新配置信息)'
'envelope信封,交易就封装在其中,orderer节点收到的就是信封,并不会打开,不会对交易进行处理,配置交易除外,配置交易就是发给orderer节点的'
ProposeConfigUpdate(env *cb.Envelope) (*cb.ConfigEnvelope, error)
}
type chainSupport struct {
*ledgerResources //账本资源类,配置、账本读写对象,匿名对象
chain Chain //链的接口(chain对象(定义了一种orderer节点消息注入的方法))
cutter blockcutter.Receiver //区块切割(广播消息接受器)
filters *filter.RuleSet //过滤器(规则集),过滤空交易,过滤交易签名错误的交易
signer crypto.LocalSigner // 签名对象,一般由msp实现
lastConfig uint64 //最新的配置信息所在的区块高度
lastConfigSeq uint64 //最新配置信息的序列号
}
func newChainSupport(
filters *filter.RuleSet, //过滤器对象
ledgerResources *ledgerResources, //账本配置资源对象,配置、账本读写对象,匿名对象
consenters map[string]Consenter, //支持的共识机制map
signer crypto.LocalSigner, //签名对象
) *chainSupport {
cutter := blockcutter.NewReceiverImpl(ledgerResources.SharedConfig(), filters) '生成区块切割对象(根据账本资源配置注册区块切割器)'
consenterType := ledgerResources.SharedConfig().ConsensusType()'(根据配置查询orderer启动时的共识机制)设置共识机制类型'
consenter, ok := consenters[consenterType]'(共识机制类型对应的共识机制对象)'
if !ok {
logger.Fatalf("Error retrieving consenter of type: %s", consenterType)
}
//赋值
cs := &chainSupport{
ledgerResources: ledgerResources,
cutter: cutter,
filters: filters,
signer: signer,
}
//序列号
cs.lastConfigSeq = cs.Sequence()
var err error
lastBlock := ledger.GetBlock(cs.Reader(), cs.Reader().Height()-1)//获取最新区块
// If this is the genesis block, the lastconfig field may be empty, and, the last config is necessary 0
// so no need to initialize lastConfig
'获取最新的区块配置信息'
if lastBlock.Header.Number != 0 {
cs.lastConfig, err = utils.GetLastConfigIndexFromBlock(lastBlock)
if err != nil {
logger.Fatalf("[channel: %s] Error extracting last config block from block metadata: %s", cs.ChainID(), err)
}
}
metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER)'(获取某个区块里的元数据)元数据主要保存的是一条链上的配置信息'
// Assuming a block created with cb.NewBlock(), this should not
// error even if the orderer metadata is an empty byte slice
if err != nil {
logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", cs.ChainID(), err)
}
logger.Debugf("[channel: %s] Retrieved metadata for tip of chain (blockNumber=%d, lastConfig=%d, lastConfigSeq=%d): %+v", cs.ChainID(), lastBlock.Header.Number, cs.lastConfig, cs.lastConfigSeq, metadata)
cs.chain, err = consenter.HandleChain(cs, metadata) //根据元数据填充chain对象(获取链的引用)
if err != nil {
logger.Fatalf("[channel: %s] Error creating consenter: %s", cs.ChainID(), err)
}
return cs
}
'一般前一个过滤器没有通过后面的不会执行,会将交易拒绝'
// createStandardFilters creates the set of filters for a normal (non-system) chain
'给非系统链创建过滤器'
func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet {
return filter.NewRuleSet([]filter.Rule{
filter.EmptyRejectRule,
sizefilter.MaxBytesRule(ledgerResources.SharedConfig()),
sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
configtxfilter.NewFilter(ledgerResources),
filter.AcceptRule,
})
}
// createSystemChainFilters creates the set of filters for the ordering system chain
'为系统链创建过滤器'
func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet {
return filter.NewRuleSet([]filter.Rule{
filter.EmptyRejectRule,
sizefilter.MaxBytesRule(ledgerResources.SharedConfig()),
sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
newSystemChainFilter(ledgerResources, ml),
configtxfilter.NewFilter(ledgerResources),
filter.AcceptRule,
})
}
'链的启动方法'
func (cs *chainSupport) start() {
cs.chain.Start()
}
'获取签名头'
func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) {
return cs.signer.NewSignatureHeader()
}
'签名,即在消息的头部加上签名头'
func (cs *chainSupport) Sign(message []byte) ([]byte, error) {
return cs.signer.Sign(message)
}
'获取过滤器方法'
func (cs *chainSupport) Filters() *filter.RuleSet {
return cs.filters
}
'返回区块切割器'
func (cs *chainSupport) BlockCutter() blockcutter.Receiver {
return cs.cutter
}
'账本读取器,返回账本资源类'
func (cs *chainSupport) Reader() ledger.Reader {
return cs.ledger
}
'接受消息方法'
func (cs *chainSupport) Enqueue(env *cb.Envelope) bool {
return cs.chain.Enqueue(env)
}
'检查链上是否有错误'
func (cs *chainSupport) Errored() <-chan struct{} {
return cs.chain.Errored()
}
'创建新区块'
func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
return ledger.CreateNextBlock(cs.ledger, messages)
}
func (cs *chainSupport) addBlockSignature(block *cb.Block) {
logger.Debugf("%+v", cs)
logger.Debugf("%+v", cs.signer)
blockSignature := &cb.MetadataSignature{
SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
}
// Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata
// information required beyond the fact that the metadata item is signed.
blockSignatureValue := []byte(nil)
blockSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes()))
block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{
Value: blockSignatureValue,
Signatures: []*cb.MetadataSignature{
blockSignature,
},
})
}
func (cs *chainSupport) addLastConfigSignature(block *cb.Block) {
configSeq := cs.Sequence()
if configSeq > cs.lastConfigSeq {
logger.Debugf("[channel: %s] Detected lastConfigSeq transitioning from %d to %d, setting lastConfig from %d to %d", cs.ChainID(), cs.lastConfigSeq, configSeq, cs.lastConfig, block.Header.Number)
cs.lastConfig = block.Header.Number
cs.lastConfigSeq = configSeq
}
lastConfigSignature := &cb.MetadataSignature{
SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
}
lastConfigValue := utils.MarshalOrPanic(&cb.LastConfig{Index: cs.lastConfig})
logger.Debugf("[channel: %s] About to write block, setting its LAST_CONFIG to %d", cs.ChainID(), cs.lastConfig)
lastConfigSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes()))
block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{
Value: lastConfigValue,
Signatures: []*cb.MetadataSignature{
lastConfigSignature,
},
})
}
'保存区块'
func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block {
//过滤器额外操作
for _, committer := range committers {
committer.Commit()
}
// Set the orderer-related metadata field
//写与orderer节点相关的元数据
if encodedMetadataValue != nil {
block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = utils.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue})
}
//区块签名
cs.addBlockSignature(block)
//区块配置签名
cs.addLastConfigSignature(block)
//将区块写入账本
err := cs.ledger.Append(block)
if err != nil {
logger.Panicf("[channel: %s] Could not append block: %s", cs.ChainID(), err)
}
logger.Debugf("[channel: %s] Wrote block %d", cs.ChainID(), block.GetHeader().Number)
return block
}
'返回账本里的区块高度'
func (cs *chainSupport) Height() uint64 {
return cs.Reader().Height()
}
区块切割也是orderer的一大重要内容在上面的chainsupport类中有用到 ,相关内容保存在blockcutter包中。区块切割的整个实现看起来还是很简单的,具体就是分成几种需要切割的情况进行检测,检测到就进行切割,
- 1 当前交易过大或者需要隔离一般是配置交易
- 2 加上当前交易消息队列容量超出限制
- 3 加上当前交易消息队列数量超出限制
其中的cut方法就是返回当前消息队列(指针)并置空,传递到ordered方法中通过标记调用相关的方法实现切割。
cutter blockcutter.Receiver //区块切割(广播消息接受器)
- blockcutter包
func (r *receiver) Ordered(msg *cb.Envelope) (messageBatches [][]*cb.Envelope, committerBatches [][]filter.Committer, validTx bool, pending bool) {
// The messages must be filtered a second time in case configuration has changed since the message was received
//对消息进行再次过滤,第一次是在orderer节点接受到消息时
committer, err := r.filters.Apply(msg)
if err != nil {
logger.Debugf("Rejecting message: %s", err)
return // We don't bother to determine `pending` here as it's not processed in error case
}
// message is valid
//把交易标记为有效,是个返回值
validTx = true
//计算交易体所占存储空间,消息体body即payload大小加上签名大小
messageSizeBytes := messageSizeBytes(msg)
//处理需要隔离的消息一般是配置交易需要被单独切割到一个区块中 或者 某个消息所占存储容量超过最大限制则进行切割
if committer.Isolated() || messageSizeBytes > r.sharedConfigManager.BatchSize().PreferredMaxBytes {
if committer.Isolated() {
logger.Debugf("Found message which requested to be isolated, cutting into its own batch")
} else {
logger.Debugf("The current message, with %v bytes, is larger than the preferred batch size of %v bytes and will be isolated.", messageSizeBytes, r.sharedConfigManager.BatchSize().PreferredMaxBytes)
}
//此时之前的交易队列里的交易就需要打包了
// cut pending batch, if it has any messages
if len(r.pendingBatch) > 0 {
messageBatch, committerBatch := r.Cut()
messageBatches = append(messageBatches, messageBatch)
committerBatches = append(committerBatches, committerBatch)
}
//再单独打包当前的这个交易
// create new batch with single message
messageBatches = append(messageBatches, []*cb.Envelope{msg})
committerBatches = append(committerBatches, []filter.Committer{committer})
return
}
messageWillOverflowBatchSizeBytes := r.pendingBatchSizeBytes+messageSizeBytes > r.sharedConfigManager.BatchSize().PreferredMaxBytes
//如果加上当前的消息容量超出最大限制则进行切割
if messageWillOverflowBatchSizeBytes {
logger.Debugf("The current message, with %v bytes, will overflow the pending batch of %v bytes.", messageSizeBytes, r.pendingBatchSizeBytes)
logger.Debugf("Pending batch would overflow if current message is added, cutting batch now.")
messageBatch, committerBatch := r.Cut()
messageBatches = append(messageBatches, messageBatch)
committerBatches = append(committerBatches, committerBatch)
}
//容量没有超限时加入消息队列 待切割的队列
logger.Debugf("Enqueuing message into batch")
r.pendingBatch = append(r.pendingBatch, msg)
r.pendingBatchSizeBytes += messageSizeBytes
r.pendingCommitters = append(r.pendingCommitters, committer)
pending = true
//消息队列长度超限进行切割
if uint32(len(r.pendingBatch)) >= r.sharedConfigManager.BatchSize().MaxMessageCount {
logger.Debugf("Batch size met, cutting batch")
messageBatch, committerBatch := r.Cut()
messageBatches = append(messageBatches, messageBatch)
committerBatches = append(committerBatches, committerBatch)
pending = false
}
return
}
//返回需要切割的交易队列pendingBatch和pendingcommitters并将其置空
// Cut returns the current batch and starts a new one
func (r *receiver) Cut() ([]*cb.Envelope, []filter.Committer) {
batch := r.pendingBatch
r.pendingBatch = nil
committers := r.pendingCommitters
r.pendingCommitters = nil
r.pendingBatchSizeBytes = 0
return batch, committers
}
//返回交易大小,消息体加上签名的大小
func messageSizeBytes(message *cb.Envelope) uint32 {
return uint32(len(message.Payload) + len(message.Signature))
}
接着看一下solo共识机制的实现,整个solo共识(排序过程)就是不断的收集消息(交易)当交易积累到最大值或者超时就进行区块切割,区块切割借助上面的区块切割器实现,然后把区块添加到orderer本地的临时账本中去
- solo/consensus
func (ch *chain) main() {
var timer <-chan time.Time//定时器
for {
select {
//获取一个交易,发送给区块切割器,进行检查切割
case msg := <-ch.sendChan:
batches, committers, ok, _ := ch.support.BlockCutter().Ordered(msg)
//交易有效、且无新区块产生,计时器的值为nil,则重置计时器
if ok && len(batches) == 0 && timer == nil {
timer = time.After(ch.support.SharedConfig().BatchTimeout())
continue
}
//有新区块产生,依次生成区块保存在orderer上的临时账本
for i, batch := range batches {
block := ch.support.CreateNextBlock(batch)
ch.support.WriteBlock(block, committers[i], nil)
}
//有区块产生打包后重置计时器
if len(batches) > 0 {
timer = nil
}
//计时器触发,立即进行切割
case <-timer:
//clear the timer
timer = nil
batch, committers := ch.support.BlockCutter().Cut()
//超时没有交易产生,报错
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, committers, nil)
//收到退出信号,退出
case <-ch.exitChan:
logger.Debugf("Exiting")
return
}
}
}