区块链教程Fabric1.0源代码分析Peer peer chaincode命令及子命令实现

简介:

  兄弟连区块链教程Fabric1.0源代码分析Peer peer chaincode命令及子命令实现,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

Fabric 1.0源代码笔记 之 Peer #peer chaincode命令及子命令实现

1、peer chaincode install子命令实现(安装链码)

1.0、peer chaincode install子命令概述

peer chaincode install,将链码的源码和环境封装为一个链码安装打包文件,并传输到背书节点。

peer chaincode install支持如下两种方式:

  • 指定代码方式,peer chaincode install -n <链码名称> -v <链码版本> -p <链码路径>
  • 基于链码打包文件方式,peer chaincode install <链码打包文件>
    图片描述

1.1、初始化Endorser客户端

cf, err = InitCmdFactory(true, false)
//代码在peer/chaincode/install.go

cf, err = InitCmdFactory(true, false)代码如下:

func InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error) {
    var err error
    var endorserClient pb.EndorserClient
    if isEndorserRequired {
        //获取Endorser客户端
        endorserClient, err = common.GetEndorserClientFnc() //func GetEndorserClient() (pb.EndorserClient, error)
    }
    //获取签名
    signer, err := common.GetDefaultSignerFnc()
    var broadcastClient common.BroadcastClient
    if isOrdererRequired {
        //此处未用到,暂略
    }
    //构造ChaincodeCmdFactory
    return &ChaincodeCmdFactory{
        EndorserClient:  endorserClient,
        Signer:          signer,
        BroadcastClient: broadcastClient,
    }, nil
}
//代码在peer/chaincode/common.go

1.2、构造ChaincodeDeploymentSpec消息(链码信息及链码文件打包)

if ccpackfile == "" { //指定代码方式,重新构造构造ChaincodeDeploymentSpec消息
    ccpackmsg, err = genChaincodeDeploymentSpec(cmd, chaincodeName, chaincodeVersion)
} else { //基于链码打包文件方式,直接读取ChaincodeDeploymentSpec消息
    var cds *pb.ChaincodeDeploymentSpec
    ccpackmsg, cds, err = getPackageFromFile(ccpackfile)
}
//代码在peer/chaincode/install.go

ccpackmsg, err = genChaincodeDeploymentSpec(cmd, chaincodeName, chaincodeVersion)代码如下:

func genChaincodeDeploymentSpec(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) {
    //已经存在,直接报错
    if existed, _ := ccprovider.ChaincodePackageExists(chaincodeName, chaincodeVersion); existed {
        return nil, fmt.Errorf("chaincode %s:%s already exists", chaincodeName, chaincodeVersion)
    }
    spec, err := getChaincodeSpec(cmd)
    cds, err := getChaincodeDeploymentSpec(spec, true)
    return cds, nil
}
//代码在peer/chaincode/install.go

spec, err := getChaincodeSpec(cmd)代码如下:

func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) {
    spec := &pb.ChaincodeSpec{}
    err := checkChaincodeCmdParams(cmd) //检查参数合法性
    input := &pb.ChaincodeInput{}
    //flags.StringVarP(&chaincodeCtorJSON, "ctor", "c", "{}",ctor为链码具体执行参数信息,默认为{}
    err := json.Unmarshal([]byte(chaincodeCtorJSON), &input)
    //flags.StringVarP(&chaincodeLang, "lang", "l", "golang",lang为链码的编写语言,默认为golang
    chaincodeLang = strings.ToUpper(chaincodeLang)
    spec = &pb.ChaincodeSpec{
        Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
        ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion},
        Input:       input,
    }
    return spec, nil
}
//代码在peer/chaincode/common.go

cds, err := getChaincodeDeploymentSpec(spec, true)代码如下:

func getChaincodeDeploymentSpec(spec *pb.ChaincodeSpec, crtPkg bool) (*pb.ChaincodeDeploymentSpec, error) {
    var codePackageBytes []byte
    if chaincode.IsDevMode() == false && crtPkg {
        var err error
        err = checkSpec(spec) //检查spec合法性
        codePackageBytes, err = container.GetChaincodePackageBytes(spec) //打包链码文件及依赖文件
    }
    //构造ChaincodeDeploymentSpec
    chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}
    return chaincodeDeploymentSpec, nil
//代码在peer/chaincode/common.go

1.3、创建lscc Proposal并签名

creator, err := cf.Signer.Serialize() //获取签名者
//按ChaincodeDeploymentSpec构造Proposal,即链码ChaincodeDeploymentSpec消息作为参数传递给lscc系统链码并调用
//调用createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy")
prop, _, err := utils.CreateInstallProposalFromCDS(msg, creator) 
var signedProp *pb.SignedProposal
signedProp, err = utils.GetSignedProposal(prop, cf.Signer) //签名提案
//代码在peer/chaincode/install.go

createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy")代码如下:

func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) {
    var ccinp *peer.ChaincodeInput
    var b []byte
    var err error
    b, err = proto.Marshal(msg)
    switch propType {
    case "deploy":
        fallthrough
    case "upgrade": 
        cds, ok := msg.(*peer.ChaincodeDeploymentSpec)
        ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), []byte(chainID), b, policy, escc, vscc}}
    case "install": 
        ccinp = &peer.ChaincodeInput{Args: [][]byte{[]byte(propType), b}}
    }
    lsccSpec := &peer.ChaincodeInvocationSpec{ //构造lscc ChaincodeInvocationSpec
        ChaincodeSpec: &peer.ChaincodeSpec{
            Type:        peer.ChaincodeSpec_GOLANG,
            ChaincodeId: &peer.ChaincodeID{Name: "lscc"},
            Input:       ccinp}}

    return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lsccSpec, creator)
}
//代码在protos/utils/proputils.go

1.4、提交并处理Proposal

proposalResponse, err := cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
//代码在peer/chaincode/install.go

2、peer chaincode instantiate子命令实现(实例化链码)

2.0、peer chaincode instantiate概述

peer chaincode instantiate命令通过构造生命周期管理系统链码(LSCC)的交易,将安装过的链码在指定通道上进行实例化调用。
在peer上创建容器启动,并执行初始化操作。

2.1、初始化EndorserClient、Signer、及BroadcastClient

与2.1接近,附BroadcastClient初始化代码如下:

cf, err = InitCmdFactory(true, true)
//代码在peer/chaincode/instantiate.go
func InitCmdFactory(isEndorserRequired, isOrdererRequired bool) (*ChaincodeCmdFactory, error) {
    //初始化EndorserClient、Signer
    var broadcastClient common.BroadcastClient
    if isOrdererRequired {
        //flags.StringVarP(&orderingEndpoint, "orderer", "o", "", "Ordering service endpoint")
        //orderingEndpoint为orderer服务地址
        broadcastClient, err = common.GetBroadcastClientFnc(orderingEndpoint, tls, caFile)
    }
}
//代码在peer/chaincode/common.go

BroadcastClient更详细内容,参考Fabric 1.0源代码笔记 之 Peer #BroadcastClient(Broadcast客户端)

2.2、构造ChaincodeDeploymentSpec消息

spec, err := getChaincodeSpec(cmd) //构造ChaincodeSpec,参考本文1.2
//构造ChaincodeDeploymentSpec,参考本文1.2,但无法打包链码文件
cds, err := getChaincodeDeploymentSpec(spec, false)
//代码在peer/chaincode/instantiate.go

2.3、创建lscc Proposal并签名

creator, err := cf.Signer.Serialize() //获取签名者
//policyMarhsalled为flags.StringVarP(&policy, "policy", "P", common.UndefinedParamValue,即链码关联的背书策略
//即调用 createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy"),参考本文1.3
prop, _, err := utils.CreateDeployProposalFromCDS(chainID, cds, creator, policyMarhsalled, []byte(escc), []byte(vscc))
var signedProp *pb.SignedProposal
signedProp, err = utils.GetSignedProposal(prop, cf.Signer) //签名提案
//代码在peer/chaincode/instantiate.go

2.4、提交并处理Proposal、获取Proposal响应并创建签名交易Envelope

proposalResponse, err := cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
if proposalResponse != nil {
    env, err := utils.CreateSignedTx(prop, cf.Signer, proposalResponse) //由Proposal创建签名交易Envelope
    return env, nil
}
//代码在peer/chaincode/instantiate.go

env, err := utils.CreateSignedTx(prop, cf.Signer, proposalResponse)代码如下:

func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
    hdr, err := GetHeader(proposal.Header) //反序列化为common.Header
    pPayl, err := GetChaincodeProposalPayload(proposal.Payload) //反序列化为peer.ChaincodeProposalPayload
    signerBytes, err := signer.Serialize() //signer序列化
    shdr, err := GetSignatureHeader(hdr.SignatureHeader) //反序列化为common.SignatureHeader
    if bytes.Compare(signerBytes, shdr.Creator) != 0 { //Proposal创建者需与当前签名者相同
        return nil, fmt.Errorf("The signer needs to be the same as the one referenced in the header")
    }
    hdrExt, err := GetChaincodeHeaderExtension(hdr) //Header.ChannelHeader反序列化为peer.ChaincodeHeaderExtension

    var a1 []byte
    for n, r := range resps {
        if n == 0 {
            a1 = r.Payload
            if r.Response.Status != 200 { //检查Response.Status是否为200
                return nil, fmt.Errorf("Proposal response was not successful, error code %d, msg %s", r.Response.Status, r.Response.Message)
            }
            continue
        }
        if bytes.Compare(a1, r.Payload) != 0 { //检查所有ProposalResponse.Payload是否相同
            return nil, fmt.Errorf("ProposalResponsePayloads do not match")
        }
    }

    endorsements := make([]*peer.Endorsement, len(resps))
    for n, r := range resps {
        endorsements[n] = r.Endorsement
    }

    //如下为逐层构建common.Envelope
    cea := &peer.ChaincodeEndorsedAction{ProposalResponsePayload: resps[0].Payload, Endorsements: endorsements}
    propPayloadBytes, err := GetBytesProposalPayloadForTx(pPayl, hdrExt.PayloadVisibility)
    cap := &peer.ChaincodeActionPayload{ChaincodeProposalPayload: propPayloadBytes, Action: cea}
    capBytes, err := GetBytesChaincodeActionPayload(cap)
    taa := &peer.TransactionAction{Header: hdr.SignatureHeader, Payload: capBytes}
    taas := make([]*peer.TransactionAction, 1)
    taas[0] = taa
    tx := &peer.Transaction{Actions: taas}
    txBytes, err := GetBytesTransaction(tx)
    payl := &common.Payload{Header: hdr, Data: txBytes}
    paylBytes, err := GetBytesPayload(payl)
    sig, err := signer.Sign(paylBytes)
    return &common.Envelope{Payload: paylBytes, Signature: sig}, nil
}

//代码在protos/utils/txutils.go

common.Envelope更详细内容,参考:Fabric 1.0源代码笔记 之 附录-关键数据结构

2.5、向orderer广播交易Envelope

err = cf.BroadcastClient.Send(env)
//代码在peer/chaincode/instantiate.go

3、peer chaincode invoke子命令实现(调用链码)

3.0、peer chaincode invoke概述

通过invoke命令可以调用运行中的链码的方法。

3.1、初始化EndorserClient、Signer、及BroadcastClient

参考本文1.1和2.1。

cf, err = InitCmdFactory(true, true)
//代码在peer/chaincode/invoke.go

3.2、构造ChaincodeInvocationSpec

spec, err := getChaincodeSpec(cmd) //构造ChaincodeSpec
invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec} //构造ChaincodeInvocationSpec
//代码在peer/chaincode/common.go

3.3、创建Chaincode Proposal并签名

creator, err := signer.Serialize()
var prop *pb.Proposal
prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
var signedProp *pb.SignedProposal
signedProp, err = putils.GetSignedProposal(prop, signer) //Proposal签名
//代码在peer/chaincode/common.go

3.4、提交并处理Proposal、获取Proposal响应

var proposalResp *pb.ProposalResponse
proposalResp, err = endorserClient.ProcessProposal(context.Background(), signedProp)
//代码在peer/chaincode/common.go

3.5、创建签名交易Envelope并向orderer广播交易Envelope

if invoke {
    env, err := putils.CreateSignedTx(prop, signer, proposalResp) //创建签名交易
    err = bc.Send(env) //广播交易
}
//代码在peer/chaincode/common.go

4、peer chaincode query子命令实现(查询链码)

与3、peer chaincode invoke子命令实现(调用链码)基本相同,区别在于提交并处理Proposal后,不再创建交易以及广播交易。

相关文章
|
存储 供应链 监控
区块链技术在供应链管理中的应用与前景分析
随着信息化时代的到来,供应链管理面临着越来越多的挑战和机遇。本文主要探讨了区块链技术在供应链管理中的应用,以及未来的发展前景。通过对区块链技术的特点和优势进行分析,结合实际案例和趋势展望,展示了区块链技术在提升供应链透明度、效率和安全性方面的潜力,以及未来发展的可能方向。
|
安全 区块链
区块链积分商城系统开发详细指南//需求功能/指南教程/源码流程
Developing a blockchain points mall system involves multiple aspects such as blockchain technology, smart contracts, front-end development, and business logic design. The following is the general process for developing a blockchain points mall system
|
JSON 数据格式
【Azure Fabric Service】演示使用PowerShell命令部署SF应用程序(.NET)
本文详细介绍了在中国区微软云Azure上使用Service Fabrics服务时,通过PowerShell命令发布.NET应用的全过程。由于Visual Studio 2022无法直接发布应用,需借助PowerShell脚本完成部署。文章分三步讲解:首先在Visual Studio 2022中打包应用部署包,其次连接SF集群并上传部署包,最后注册应用类型、创建实例并启动服务。过程中涉及关键参数如服务器证书指纹和服务端证书指纹的获取,并附带图文说明,便于操作。参考官方文档,帮助用户成功部署并运行服务。
444 73
|
存储 算法 API
面向企业的区块链教程(一)(2)
面向企业的区块链教程(一)
429 6
|
安全 区块链
Massa Layer 1区块链 POS 安全性分析
Massa Labs 回应 Certik 的挑战,通过严格的数学分析证明了其权益证明系统的安全性,抵抗了潜在攻击者试图操纵随机抽签的企图。
214 0
Massa Layer 1区块链 POS 安全性分析
|
存储 供应链 安全
基于区块链技术的智能合约安全性分析
【5月更文挑战第31天】本文深入探讨了区块链技术中智能合约的安全性问题,通过分析现有智能合约的安全漏洞和攻击手段,提出了一系列增强智能合约安全性的策略。文章首先介绍了区块链和智能合约的基本概念,随后详细讨论了智能合约面临的安全挑战,包括代码漏洞、重入攻击等问题,并对比分析了不同平台下智能合约的安全性差异。最后,文章提出了一系列提高智能合约安全性的建议,旨在为区块链应用的健康发展提供参考。
|
负载均衡 微服务 Windows
【Azure微服务 Service Fabric 】使用az命令创建Service Fabric集群
【Azure微服务 Service Fabric 】使用az命令创建Service Fabric集群
224 0
|
存储 算法 安全
区块链系统开发技术规则分析
区块链核心技术包括:1) 哈希算法,利用单向函数将任意数据转化为固定长度代码,确保安全验证;2) 非对称加密,使用公钥和私钥一对进行加密解密,保证信息安全;3) 共识机制,如PoW、PoS、DPoS等,实现快速交易验证和确认;4) 智能合约,自动执行的可信代码,一旦编写即不可更改,用于自动化交易;5) 分布式存储,将数据分散存储在网络各处,涵盖结构化、非结构化和半结构化数据。
|
供应链 区块链 数据安全/隐私保护
探索区块链技术在金融领域的应用与前景分析
本文将深入探讨区块链技术在金融领域的具体应用场景,分析其优势与挑战,并展望未来发展趋势。通过案例分析和技术解析,揭示区块链技术在金融行业中的革新意义及前景。
2531 15
|
存储 安全 区块链
元宇宙与区块链技术的关系可以从多个角度进行阐述。以下是对这两者之间关系的详细分析
**元宇宙:虚拟世界融合现实元素,强调交互与沉浸;区块链:去中心化、安全的分布式账本。两者结合,区块链确保元宇宙中虚拟资产安全、支付高效、身份验证私密、治理透明,支撑其经济体系与用户信任,驱动未来发展。**

热门文章

最新文章