区块链教程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后,不再创建交易以及广播交易。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
区块链教程Fabric1.0源代码分析Peer EndorserClient(Endorser客户端)
兄弟连区块链教程Fabric1.0源代码分析Peer EndorserClient(Endorser客户端),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 Fabric 1.0源代码笔记 之 Peer #EndorserClient(Endorser客户端) 1、EndorserClient概述 EndorserClient相关代码分布如下: protos/peer/peer.pb.go,EndorserClient接口及实现。 peer/common/common.go,EndorserClient相关工具函数。 2、EndorserClient接口定义 type EndorserClient interface { //处理Proposal ProcessProposal(ctx context.Context, in *SignedProposal, opts ...grpc.CallOption) (*ProposalResponse, err...
- 下一篇
如何用 60 行代码爬取知乎神回复?
知乎上经常会有很多令人忍俊不禁的神回复,初看之下拍案叫绝,细思之下更是回味无穷。本文就来介绍下如何爬取知乎的神回复,揭晓其背后的原理。 知乎神回复都有些什么特点呢?我们先来观察一下: 大家看出什么规律了么?短小精辟有没有?赞同很多有没有?所以爬取知乎神回复我们只要爬取那些赞同多又字数少的回答就可以。简单的两个步骤就能实现,第一步爬取知乎回答,第二部筛选回答。是不是很easy? 01 爬取知乎回答 第一步我们爬取知乎上的回答。知乎上的回答太多了,一下子爬取所有的回答会很费时,我们可以选定几个话题,爬取这几个话题里的内容。 下面的函数用于爬取某一个指定话题的内容: def get_answers_by_page(topic_id, page_no): offset = page_no * 10 url = <topic_url> # topic_url是这个话题对应的url headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, l...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Mario游戏-低调大师作品
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G