fabric1.0学习笔记

Posted 这是谁的部将?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fabric1.0学习笔记相关的知识,希望对你有一定的参考价值。

fabric1.0学习笔记(1)
fabric1.0学习笔记(2)

一、fabric1.0目录结构(只列出了主要的文件夹)

  • bccsp 密码学相关:加密签名及证书等,将相关函数抽象成了一组接口
  • bddtests 一种新的软件开发模式:行为驱动开发 需求->开发
  • common 公共库:包括错误处理、日志处理、账本存储及各种工具
  • core 核心库:组件核心逻辑
  • devenv 开发环境:用的是vagrant
  • docs 文档:文档相关的内容
  • events 事件监听:事件监听机制,例如确定某一笔交易已经包括到区块中
  • example 例子:里面包括了一些fabric网络的例子
  • gossip gossip协议:最终一致性共识算法,用于组织内部的区块同步
  • images 镜像:用于docker镜像打包
  • msp 成员服务管理:member service provider证书管理
  • orderer orderer模块:orderer(排序)节点入口
  • peer peer模块:peer(记账)节点入口
  • proposals 提案:新功能提案
  • protos 数据定义:包括了几乎所有fabric的数据结构、数据服务的定义。

阅读源码需最好用ide方便查看代码之间的引用,这里选用的是goland,把fabric文件放到gopath下,编译器import首先寻找的是gopath

因为orderer节点相当于fabric网络中的一个中心节点,所以从orderer的代码开始看
代码注释括号里的内容是个人理解可能认识的有问题

  • orderer的main函数
func main() {

	kingpin.Version("0.0.1")
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {

	// "start" command
	case start.FullCommand():
		logger.Infof("Starting %s", metadata.GetVersionInfo())
	
        '载入配置信息'
		conf := config.Load()
		
		'初始化日志级别'
		initializeLoggingLevel(conf)
		
		'启动profile服务(里面涉及的pprof是性能分析服务)'
		initializeProfilingService(conf)
		
		'初始化grpc服务,(让系统监听某个端口)'
		grpcServer := initializeGrpcServer(conf)
		
		'加载本地msp服务,需要LocalMspDir,BCCSP,LocalMspID三个参数'
		initializeLocalMsp(conf)
		
		'msp证书用于签名者实例化(实例化了一个接口)'
		signer := localmsp.NewSigner()

		'初始化多链管理者,这里的manager需要着重看一下!!!'
		manager := initializeMultiChainManager(conf, signer)
		server := NewServer(manager, signer)
		ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)
		logger.Info("Beginning to serve requests")
		grpcServer.Start()
	// "version" command
	case version.FullCommand():
		fmt.Println(metadata.GetVersionInfo())
	}

}
  • manager包
// Manager coordinates the creation and access of chains
type Manager interface {
	// GetChain retrieves the chain support for a chain (and whether it exists)
	'根据链的名称获取一个链对象(chainsupport是个接口,并没有对链直接操作)'
	GetChain(chainID string) (ChainSupport, bool)

	// SystemChannelID returns the channel ID for the system channel
	'获取系统链的ID(系统链是一个空链,用于引导产生新的链,因为交易都要属于一个链,所以创建链时的交易就需要一个初始链即系统链)'
	SystemChannelID() string

	// NewChannelConfig returns a bare bones configuration ready for channel
	// creation request to be applied on top of it
	'生成或更新链的配置'
	NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error)
}

'这是一个配置资源,每个链的配置都会打包在这个类里'
type configResources struct {
	configtxapi.Manager
}

'获取orderer节点的配置'
func (cr *configResources) SharedConfig() config.Orderer {
	oc, ok := cr.OrdererConfig()
	if !ok {
		logger.Panicf("[channel %s] has no orderer configuration", cr.ChainID())
	}
	return oc
}
'账本资源类,包括了账本的配置资源和账本的读写对象,可看作对账本进行操作的入口'
type ledgerResources struct {
	*configResources
	ledger ledger.ReadWriter
}
'manager实现类'
type multiLedger struct {
	chains          map[string]*chainSupport]   多个链的对象
	consenters      map[string]Consenter        目前支持的共识机制
	ledgerFactory   ledger.Factory              账本工厂
	signer          crypto.LocalSigner          签名对象(方法),一般是msp,msp实现signer的接口
	systemChannelID string                      系统链名称
	systemChannel   *chainSupport				系统链对象
}
'获取区块里最新的配置交易解码后打印出来,reader是用来操作账本的'
func getConfigTx(reader ledger.Reader) *cb.Envelope {
	lastBlock := ledger.GetBlock(reader, reader.Height()-1)
	index, err := utils.GetLastConfigIndexFromBlock(lastBlock)
	if err != nil {
		logger.Panicf("Chain did not have appropriately encoded last config in its latest block: %s", err)
	}
	configBlock := ledger.GetBlock(reader, index)
	if configBlock == nil {
		logger.Panicf("Config block does not exist")
	}

	return utils.ExtractEnvelopeOrPanic(configBlock, 0)
}

// NewManagerImpl produces an instance of a Manager

'输入账本工厂、支持的共识机制、签名对象返回一个manager实例'
func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager {
	ml := &multiLedger{
		chains:        make(map[string]*chainSupport),
		ledgerFactory: ledgerFactory,
		consenters:    consenters,
		signer:        signer,
	}
	'读取本地存储链的ID'
	existingChains := ledgerFactory.ChainIDs()
	for _, chainID := range existingChains {
		//通过账本工厂实例化一个账本读的对象,read ledger
		rl, err := ledgerFactory.GetOrCreate(chainID)
		if err != nil {
			logger.Panicf("Ledger factory reported chainID %s but could not retrieve it: %s", chainID, err)
		}
		'获取链最新的配置交易'
		configTx := getConfigTx(rl)
		if configTx == nil {
			logger.Panic("Programming error, configTx should never be nil here")
		}
		'将配置交易和ledger对象绑定起来'
		ledgerResources := ml.newLedgerResources(configTx)
		chainID := ledgerResources.ChainID()
		//判断是否有创建其他链的权限
		if _, ok := ledgerResources.ConsortiumsConfig(); ok {
			if ml.systemChannelID != "" {
				logger.Panicf("There appear to be two system chains %s and %s", ml.systemChannelID, chainID)
			}
			chain := newChainSupport(createSystemChainFilters(ml, ledgerResources),
				ledgerResources,
				consenters,
				signer)
			logger.Infof("Starting with system channel %s and orderer type %s", chainID, chain.SharedConfig().ConsensusType())
			ml.chains[chainID] = chain
			ml.systemChannelID = chainID
			ml.systemChannel = chain
			// We delay starting this chain, as it might try to copy and replace the chains map via newChain before the map is fully built
			defer chain.start()//延迟启动该链
		} else {
			logger.Debugf("Starting chain: %s", chainID)
			chain := newChainSupport(createStandardFilters(ledgerResources),
				ledgerResources,
				consenters,
				signer)
			ml.chains[chainID] = chain
			chain.start()
		}

	}
	'最后检验'
	if ml.systemChannelID == "" {
		logger.Panicf("No system chain found.  If bootstrapping, does your system channel contain a consortiums group definition?")
	}

	return ml
}
'获取系统链(通道)名称'
func (ml *multiLedger) SystemChannelID() string {
	return ml.systemChannelID
}
'(返回orderer节点中的一条链,以链对象chainsupport形式存储)'
// GetChain retrieves the chain support for a chain (and whether it exists)
func (ml *multiLedger) GetChain(chainID string) (ChainSupport, bool) {
	cs, ok := ml.chains[chainID]
	return cs, ok
}

'新建账本资源,即新建一个账本并返回新账本的资源类作为账本的入口'
func (ml *multiLedger) newLedgerResources(configTx *cb.Envelope) *ledgerResources {
	initializer := configtx.NewInitializer()
	configManager, err := configtx.NewManagerImpl(configTx, initializer, nil)
	if err != nil {
		logger.Panicf("Error creating configtx manager and handlers: %s", err)
	}
		'(这里的configManager是单条链上的manager,本文件是orderer上的manager是multiManager)'
	chainID := configManager.ChainID()

	ledger, err := ml.ledgerFactory.GetOrCreate(chainID)
	if err != nil {
		logger.Panicf("Error getting ledger for %s", chainID)
	}

	return &ledgerResources{
		configResources: &configResources{Manager: configManager},
		ledger:          ledger,
	}
}

'创建新链(通道),会把配置信息写入新的账本中,向multiLedger的链的map中增加新链的内容'
func (ml *multiLedger) newChain(configtx *cb.Envelope) {
	ledgerResources := ml.newLedgerResources(configtx)
	ledgerResources.ledger.Append(ledger.CreateNextBlock(ledgerResources.ledger, []*cb.Envelope{configtx}))      配置信息写入新链的账本

	// Copy the map to allow concurrent reads from broadcast/deliver while the new chainSupport is
	newChains := make(map[string]*chainSupport)
	for key, value := range ml.chains {
		newChains[key] = value
	}

	cs := newChainSupport(createStandardFilters(ledgerResources), ledgerResources, ml.consenters, ml.signer)
	chainID := ledgerResources.ChainID()

	logger.Infof("Created and starting new chain %s", chainID)

	newChains[string(chainID)] = cs
	cs.start()

	ml.chains = newChains
}
'返回当前orderer节点上的链数(通道数)'
func (ml *multiLedger) channelsCount() int {
	return len(ml.chains)
}

'生成新链的配置,主要是一些检查性的工作 (新建通道配置文件,也用到了单链上的manager,应该是有区别)'
func (ml *multiLedger) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) {
	configUpdatePayload, err := utils.UnmarshalPayload(envConfigUpdate.Payload)
	if err != nil {
		return nil, fmt.Errorf("Failing initial channel config creation because of payload unmarshaling error: %s", err)
	}

	configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(configUpdatePayload.Data)
	if err != nil {
		return nil, fmt.Errorf("Failing initial channel config creation because of config update envelope unmarshaling error: %s", err)
	}

	if configUpdatePayload.Header == nil {
		return nil, fmt.Errorf("Failed initial channel config creation because config update header was missing")
	}
	channelHeader, err := utils.UnmarshalChannelHeader(configUpdatePayload.Header.ChannelHeader)

	configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
	if err != nil {
		return nil, fmt.Errorf("Failing initial channel config creation because of config update unmarshaling error: %s", err)
	}

	if configUpdate.ChannelId != channelHeader.ChannelId {
		return nil, fmt.Errorf("Failing initial channel config creation: mismatched channel IDs: '%s' != '%s'", configUpdate.ChannelId, channelHeader.ChannelId)
	}

	if configUpdate.WriteSet == nil {
		return nil, fmt.Errorf("Config update has an empty writeset")
	}

	if configUpdate.WriteSet.Groups == nil || configUpdate.WriteSet.Groups[config.ApplicationGroupKey] == nil {
		return nil, fmt.Errorf("Config update has missing application group")
	}

	if uv := configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version; uv != 1 {
		return nil, fmt.Errorf("Config update for channel creation does not set application group version to 1, was %d", uv)
	}

	consortiumConfigValue, ok := configUpdate.WriteSet.Values[config.ConsortiumKey]
	if !ok {
		return nil, fmt.Errorf("Consortium config value missing")
	}

	consortium := &cb.Consortium{}
	err = proto.Unmarshal(consortiumConfigValue.Value, consortium)
	if err != nil {
		return nil, fmt.Errorf("Error reading unmarshaling consortium name: %s", err)
	}

	applicationGroup := cb.NewConfigGroup()
	consortiumsConfig, ok := ml.systemChannel.ConsortiumsConfig()
	if !ok {
		return nil, fmt.Errorf("The ordering system channel does not appear to support creating channels")
	}

	consortiumConf, ok := consortiumsConfig.Consortiums()[consortium.Name]
	if !ok {
		return nil, fmt.Errorf("Unknown consortium name: %s", consortium.Name)
	}

	applicationGroup.Policies[config.ChannelCreationPolicyKey] = &cb.ConfigPolicy{
		Policy: consortiumConf.ChannelCreationPolicy(),
	}
	applicationGroup.ModPolicy = config.ChannelCreationPolicyKey

	// Get the current system channel config
	systemChannelGroup := ml.systemChannel.ConfigEnvelope().Config.ChannelGroup

	// If the consortium group has no members, allow the source request to have no members.  However,
	// if the consortium group has any members, there must be at least one member in the source request
	if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 &&
		len(configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups) == 0 {
		return nil, fmt.Errorf("Proposed configuration has no application group members, but consortium contains members")
	}

	// If the consortium has no members, allow the source request to contain arbitrary members
	// Otherwise, require that the supplied members are a subset of the consortium members
	if len(systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups) > 0 {
		for orgName := range configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups {
			consortiumGroup, ok := systemChannelGroup.Groups[config.ConsortiumsGroupKey].Groups[consortium.Name].Groups[orgName]
			if !ok {
				return nil, fmt.Errorf("Attempted to include a member which is not in the consortium")
			}
			applicationGroup.Groups[orgName] = consortiumGroup
		}
	}

	channelGroup := cb.NewConfigGroup()

	// Copy the system channel Channel level config to the new config
	for key, value := range systemChannelGroup.Values {
		channelGroup.Values[key] = value
		if key == config.ConsortiumKey {
			// Do not set the consortium name, we do this later
			continue
		}
	}

	for key, policy := range systemChannelGroup.Policies {
		channelGroup.Policies[key] = policy
	}

	// Set the new config orderer group to the system channel orderer group and the application group to the new application group
	channelGroup.Groups[config.OrdererGroupKey] = systemChannelGroup.Groups[config.OrdererGroupKey]
	channelGroup.Groups[config.ApplicationGroupKey] = applicationGroup
	channelGroup.Values[config.ConsortiumKey] = config.TemplateConsortium(consortium.Name).Values[config.ConsortiumKey]

	templateConfig, _ := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, configUpdate.ChannelId, ml.signer, &cb.ConfigEnvelope{
		Config: &cb.Config{
			ChannelGroup: channelGroup,
		},
	}, msgVersion, epoch)

	initializer := configtx.NewInitializer()

	// This is a very hacky way to disable the sanity check logging in the policy manager
	// for the template configuration, but it is the least invasive near a release
	pm, ok := initializer.PolicyManager().(*policies.ManagerImpl)
	if ok {
		pm.SuppressSanityLogMessages = true
		defer func() {
			pm.SuppressSanityLogMessages = false
		}()
	}

	return configtx.NewManagerImpl(templateConfig, initializer, nil)
}

以上是关于fabric1.0学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

区块链教程Fabric1.0源代码分析blockfile区块文件存储一

区块链教程Fabric1.0源代码分析配置交易-生成通道配置二

兄弟连区块链教程Fabric1.0源代码分析ledgerID数据

区块链教程Fabric1.0源代码分析Peer peer根命令入口及加载子命令二

区块链教程Fabric1.0源代码分析Ledger historydb历史数据库

学习笔记:python3,代码片段(2017)