源码分析-Fabric 1.4.2 lscc启动用户链码的过程

源码分析-Fabric 1.4.2 lscc启动用户链码的过程

lscc负责管理链码的生命周期,其就是说链码容器的启动应该是lscc触发的。但是链码容器是如何从peer chaincode instantiate 触发实例化命令到peer服务完成链码的实例化,即链码容器的启动,看了一些网上的资料机会没有讲这块的。也因为又这块二次开发的需求,所以追踪了一下Fabric源码从lscc到用户链码容器启动的全过程,在此记录一下。

客户端peer chaincode instantiate部分

fabric/peer/chaincode/instantiate.go

func instantiate(cmd *cobra.Command, cf *ChaincodeCmdFactory) (*protcommon.Envelope, error) {
   
    ...
	// instantiate is currently only supported for one peer
    proposalResponse, err := cf.EndorserClients[0].ProcessProposal(context.Background(), signedProp
    /*
    EndorserClients[0]就是这个peer本身(但是这是在客户端里呀,配置中设置好的地址,详细看cli的配置 CORE_PEER_ADDRESS=peer0.org1.example.com:7051)
    ProcessProposal是grpc定义的函数,可以在peer.pb.go中看到定义的EndorserClient和EndorserServern内容,这里是客户端调用ProcessProposal把相关内容发送给Peer Server
    Peer chaincode instantiate是客户端,但客户端的endorseClient在哪里处理的?InitCmdFactory中
    */
    ...
}

ProcessProposal可以定位到grpc的定义,这是双方交互的接口
fabric/protos/peer/peer.go

message PeerID {
    string name = 1;
}

message PeerEndpoint {
    PeerID id = 1;
    string address = 2;
}

service Endorser {
	rpc ProcessProposal(SignedProposal) returns (ProposalResponse) {}
}

接下来,看下Endorser客户端是如何处理的,如何请求服务的。

先找到cf.EndorserClients是在哪里实例化的,定位到InitCmdFactory
fabric/peer/chaincode/common.go

// InitCmdFactory init the ChaincodeCmdFactory with default clients
func InitCmdFactory(cmdName string, isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error) {
   
	var err error
	var endorserClients []pb.EndorserClient
	var deliverClients []api.PeerDeliverClient
	if isEndorserRequired {
   
		if err = validatePeerConnectionParameters(cmdName); err != nil {
   
			return nil, errors.WithMessage(err, "error validating peer connection parameters")
		}
		for i, address := range peerAddresses {
   
			var tlsRootCertFile string
			if tlsRootCertFiles != nil {
   
				tlsRootCertFile = tlsRootCertFiles[i]
			}
			//找到EndorserClient实例化的代码  
			endorserClient, err := common.GetEndorserClientFnc(address, tlsRootCertFile)
			//GetEndorserClientFnc的实例是在common/common.go/init()中构建
			if err != nil {
   
				return nil, errors.WithMessage(err, fmt.Sprintf("error getting endorser client for %s", cmdName))
			}
			endorserClients = append(endorserClients, endorserClient)
			deliverClient, err := common.GetPeerDeliverClientFnc(address, tlsRootCertFile)
			if err != nil {
   
				return nil, errors.WithMessage(err, fmt.Sprintf("error getting deliver client for %s", cmdName))
			}
			deliverClients = append(deliverClients, deliverClient)
		}
		if len(endorserClients) == 0 {
   
			return nil, errors.New("no endorser clients retrieved - this might indicate a bug")
		}
	}
	...
	return &ChaincodeCmdFactory{
   
		EndorserClients: endorserClients,
		DeliverClients:  deliverClients,
		Signer:          signer,
		BroadcastClient: broadcastClient,
		Certificate:     certificate,
	}, nil
}

通过GetEndorserClientFnc找到func GetEndorserClient(address, tlsRootCertFile string) (pb.EndorserClient, error)
fabric/peer/common/peerclient.go

// GetEndorserClient returns a new endorser client. If the both the address and
// tlsRootCertFile are not provided, the target values for the client are taken
// from the configuration settings for "peer.address" and
// "peer.tls.rootcert.file"
func GetEndorserClient(address, tlsRootCertFile string) (pb.EndorserClient, error) {
   
	var peerClient *PeerClient
	var err error
	if address != "" {
   
		peerClient, err = NewPeerClientForAddress(address, tlsRootCertFile)
	} else {
   
		peerClient, err = NewPeerClientFromEnv()
	}
	if err != nil {
   
		return nil, err
	}
	//又引出peerClient
	return peerClient.Endorser()
}

定位到peerclient.go,发现peerClient的许多方法,对应这不同的grpc客户端,这里是fabric中grpc客户端封装处理的地方,Endorser grpc客户端生成的方法func (pc *PeerClient) Endorser() (pb.EndorserClient, error)
endorser grpc client实例,fabric/peer/common/peerclient.go

// Endorser returns a client for the Endorser service
func (pc *PeerClient) Endorser() (pb.EndorserClient, error) {
   
	conn, err := pc.commonClient.NewConnection(pc.address, pc.sn)
	if err != nil {
   
		return nil, errors.WithMessage(err, fmt.Sprintf("endorser client failed to connect to %s", pc.address))
	}
	return pb.NewEndorserClient(conn), nil
}

到此,找到了endorser grpc客户端实例的创建,以及grpc的请求,调用接口ProcessProposal
我们看到实例化是启动了背书的grpc,实际上其他交易也是启动背书过程,这是fabric,区块链的特性,大多数的处理都会在背书上,所以待会我们主要看服务端的背书处理上

peer chaincode instantiate 链码实例化客户端部分已经完成


peer chaincode instantiate 链码实例化server端

服务端首先处理的是lscc的调用处理,就是lscc Invoke的地方,但如果继续看下去,就会发现,这里只是将作为参数的用户链码,存了起来,也就是说,将链码存储的是这里实现的。

fabric/core/scc/lscc/lscc.go/Invoke

// Invoke implements lifecycle functions "deploy", "start", "stop", "upgrade".
// Deploy's arguments -  {[]byte("deploy"), []byte(<chainname>), <unmarshalled pb.ChaincodeDeploymentSpec>}
//
// Invoke also implements some query-like functions
// Get chaincode arguments -  {[]byte("getid"), []byte(<chainname>), []byte(<chaincodename>)}
func (lscc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   
	args := stub.GetArgs()
	if len(args) < 1 {
   
		return shim.Error(InvalidArgsLenErr(len(args)).Error())
	}

	function := string(args[0])

	// Handle ACL:
	// 1. get the signed proposal
	sp, err := stub.GetSignedProposal()
	if err != nil {
   
		return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err))
	}

	switch function {
   
	case INSTALL:
        ...
	case DEPLOY, UPGRADE:
		// we expect a minimum of 3 arguments, the function
		// name, the chain name and deployment spec
		if len(args) < 3 {
   
			return shim.Error(InvalidArgsLenErr(len(args)).Error())
		}

		// channel the chaincode should be associated with. It
		// should be created with a register call
		channel := string(args[1])

		if !lscc.isValidChannelName(channel) {
   
			return shim.Error(InvalidChannelNameErr(channel).Error())
		}

		ac, exists := lscc.SCCProvider.GetApplicationConfig(channel)
		if !exists {
   
			logger.Panicf("programming error, non-existent appplication config for channel '%s'", channel)
		}

		// the maximum number of arguments depends on the capability of the channel
		if !ac.Capabilities().PrivateChannelData() && len(args) > 6 {
   
			return shim.Error(PrivateChannelDataNotAvailable("").Error())
		}
		if ac.Capabilities().PrivateChannelData() && len(args) > 7 {
   
			return shim.Error(InvalidArgsLenErr(len(args)).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值