作者|DeeptimanPattnaik
译者|火火酱,责编|Carol 在本文中,我将解释如何在超账本HyperledgerFabric中使用Protobuf对数据进行序列化和结构化。Protobuf简化了HyperledgerFabric中数据处理和格式化过程。它使用特殊生成的源代码产生数据,从而在同一个智能合约中轻松地写入和读取数据。 Chaincode和SmartContract
在hyperledgerfabric中,Chaincode(链码)是一个特定的程序,被用于处理由区块链网络的参与者所同意的核心业务逻辑。Hyperledgerfabric还使用了一种名为SmartContract的数据格式技术,该技术是为Chaincode中的一组特定数据模型定义的。Chaincode可以有多组SmartContract,这些SmartContract可以控制不同数据模型的事务逻辑。简单来说,SmartContract管理事务,而Chaincode管理如何部署SmartContract。
例如:如果需要将一些用户信息记录存储到分类帐中,那么我们就需要一个能够定义单个记录所需数据字段的SmartContract。 User(用户)SmartContract
typeUserstruct{ IDstring`json:"id"` Emailstring`json:"email"` Namestring`json:"name"` Mobilestring`json:"mobile"` Agestring`json:"age"` }
在该SmartContract中,有ID、电子邮件、姓名、移动电话、年龄等与个人用户记录相关的数据字段。同样,如果我们需要存储每位用户的财务记录,那么我们就需要另一种名为Financial的smartcontract。 Financial(金融)SmartContract
typeFinancialstruct{ IDstring`json:"id"` BankNamestring`json:"bankName"` IFSCCodestring`json:"ifscCode"` AccNumberstring`json:"accNumber"` CreatedDatestring`json:"createdDate"` }
这两个smartcontract将被部署到Chaincode中,并且将处理两个分类帐状态——世界状态(WorldState)和区块链的事务逻辑。 SmartContract在世界状态下主要执行Put、Get、Delete和GetHistory。 1.PutState——为每个不同的键创建新对象,或者覆盖现有对象。 2.GetState——从分类帐状态中检索不同键的对象。 3.DelState——从分类账的世界状态中移除对象。 4.GetHistoryForKey——返回跨时间键的所有交易历史记录。 所有记录都作为世界状态记录被存储在CouchDB中。对象以JSON格式存储为键值对。CouchDB能更快地从数据库中查询JSON集合。在区块链状态下,所有这些记录都被存储在字节中,并且是不可变的。 Protobuf
协议缓冲区(简称protobuf)是谷歌的序列化结构化数据,其无关语言和平台,并且具有可扩展机制。与传统的数据格式(如XML或JSON)相比,序列化结构化数据以字节为单位进行编译,因此更小、更快、更简单。 为什么要使用Protobuf?
如我们所见,有User和Financial两个smartcontract将信息存储在同一个用户的分类账中,即User存储用户的基本的信息,Financial存储用户银行账户的详细信息。 但是,如果我们从查询目的的角度来看smartcontract的话,两个数据集之间就没有关系了。我们不能为User和Financial数据模型定义相同的ID作为键,因为分类帐数据存储在键值对中,如果出现相同的键,则信息将被覆盖。 这两条记录将在分类账状态中以两个不同的ID进行存储 为了解决这个问题,Protobuf提供了一个更快、更灵活的解决方案。我们只需编写一个.proto文件来描述数据结构,在本例中,是我们要存储的Financial数据结构。 因此,protobuf消息格式的字节结果直接调用到UserSmartContract并完全删除FinancialSmartContract。 Protobuf是如何运作的?
接下来,我们将了解如何设置protobuf编译器并生成protobuf消息格式。 安装
首先,我们需要遵循一定的安装流程才能使用protobuf-compiler。 $gogetgithub.com/golang/protobuf $gogetgithub.com/golang/protobuf/proto $goget-ugithub.com/golang/protobuf/protoc-gen-go $exportPATH=$PATH:$GOPATH/bin
现在,安装protobuf-compiler $sudoaptinstallprotobuf-compiler
然后,在命令行中输入protoc’。应该会显示‘Missinginputfile’(缺少输入文件),这表示protobuf-compiler已经成功安装。 示例 首先,我们需要创建一个financial.proto文件。它由Financial类型的消息格式组成,包含四个字段:银行名称、ifsc代码、帐号、创建日期。 financial.proto
syntax="proto3"; packagemain; messageFinancial{ stringbankName=1; stringifscCode=2; stringaccNumber=3; stringcreatedDate=4; }
编译该proto文件,生成用于Financial消息格式的protobuf数据模型文件。 $protoc--go_out=.*.proto
你会看到protobuf文件已生成为financial.pb.go。该文件是与proto包兼容的数据模型,将被用于把proto消息格式转换为字节。
financial.pb.go
//Codegeneratedbyprotoc-gen-go.DONOTEDIT. //source:financial.proto packagemain import( fmt"fmt" proto"github.com/golang/protobuf/proto" math"math" ) //Referenceimportstosuppresserrorsiftheyarenototherwiseused. var_=proto.Marshal var_=fmt.Errorf var_=math.Inf //Thisisacompile-timeassertiontoensurethatthisgeneratedfile //iscompatiblewiththeprotopackageitisbeingcompiledagainst. //Acompilationerroratthislinelikelymeansyourcopyofthe //protopackageneedstobeupdated. const_=proto.ProtoPackageIsVersion3//pleaseupgradetheprotopackage typeFinancialstruct{ BankNamestring`protobuf:"bytes,1,opt,name=bankName,proto3"json:"bankName,omitempty"` IfscCodestring`protobuf:"bytes,2,opt,name=ifscCode,proto3"json:"ifscCode,omitempty"` AccNumberstring`protobuf:"bytes,3,opt,name=accNumber,proto3"json:"accNumber,omitempty"` CreatedDatestring`protobuf:"bytes,4,opt,name=createdDate,proto3"json:"createdDate,omitempty"` XXX_NoUnkeyedLiteralstruct{}`json:"-"` XXX_unrecognized[]byte`json:"-"` XXX_sizecacheint32`json:"-"` }
func(m*Financial)Reset(){*m=Financial{}} func(m*Financial)String()string{returnproto.CompactTextString(m)} func(*Financial)ProtoMessage(){
func(*Financial)Descriptor()([]byte,[]int){ returnfileDescriptor_a283ebe7677acfbc,[]int{0} }
func(m*Financial)XXX_Unmarshal(b[]byte)error{ returnxxx_messageInfo_Financial.Unmarshal(m,b) }
func(m*Financial)XXX_Marshal(b[]byte,deterministicbool)([]byte,error){ returnxxx_messageInfo_Financial.Marshal(b,m,deterministic) }
func(m*Financial)XXX_Merge(srcproto.Message){ xxx_messageInfo_Financial.Merge(m,src) }
func(m*Financial)XXX_Size()int{ returnxxx_messageInfo_Financial.Size(m) }
func(m*Financial)XXX_DiscardUnknown(){ xxx_messageInfo_Financial.DiscardUnknown(m) }
varxxx_messageInfo_Financialproto.InternalMessageInfo func(m*Financial)GetBankName()string{ ifm!=nil{ returnm.BankName } return"" }
func(m*Financial)GetIfscCode()string{ ifm!=nil{ returnm.IfscCode } return"" }
func(m*Financial)GetAccNumber()string{ ifm!=nil{ returnm.AccNumber } return"" }
func(m*Financial)GetCreatedDate()string{ ifm!=nil{ returnm.CreatedDate } return"" }
funcinit(){ proto.RegisterType((*Financial)(nil),"main.Financial") }
funcinit(){proto.RegisterFile("financial.proto",fileDescriptor_a283ebe7677acfbc)}
varfileDescriptor_a283ebe7677acfbc=[]byte{ //136bytesofagzippedFileDescriptorProto 0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xe2,0xe2,0x4f,0xcb,0xcc,0x4b, 0xcc,0x4b,0xce,0x4c,0xcc,0xd1,0x2b,0x28,0xca,0x2f,0xc9,0x17,0x62,0xc9,0x4d,0xcc, 0xcc,0x53,0x6a,0x66,0xe4,0xe2,0x74,0x83,0xc9,0x08,0x49,0x71,0x71,0x24,0x25,0xe6, 0x65,0xfb,0x25,0xe6,0xa6,0x4a,0x30,0x2a,0x30,0x6a,0x70,0x06,0xc1,0xf9,0x20,0xb9, 0xcc,0xb4,0xe2,0x64,0xe7,0xfc,0x94,0x54,0x09,0x26,0x88,0x1c,0x8c,0x2f,0x24,0xc3, 0xc5,0x99,0x98,0x9c,0xec,0x57,0x9a,0x9b,0x94,0x5a,0x24,0xc1,0x0c,0x96,0x44,0x08, 0x08,0x29,0x70,0x71,0x27,0x17,0xa5,0x26,0x96,0xa4,0xa6,0xb8,0x24,0x96,0xa4,0x4a, 0xb0,0x80,0xe5,0x91,0x85,0x92,0xd8,0xc0,0x4e,0x32,0x06,0x04,0x00,0x00,0xff,0xff, 0x44,0x01,0xf8,0x14,0xa5,0x00,0 现在,我们将在Usersmartcontract中创建一个额外的数据字段financial。 typeUserstruct{ IDstring`json:"id"` Emailstring`json:"email"` Namestring`json:"name"` Mobilestring`json:"mobile"` Agestring`json:"age"` Financialstring`json:"financial"` }
Financial消息格式参考
financial:=&Financial{ ID:"F1", BankName:"HellenicBank", IFSCCode:"1234", AccNumber:"8765", CreatedDate:"12/12/08, }
在将用户记录添加到分类帐时,还可以将financial消息格式添加到相同的Usersmartcontract中。 packagemain import( "fmt" "log" "github.com/golang/protobuf/proto" )
funcmain(){ financial:=&Financial{ BankName:"HellenicBank", IFSCCode:"1234", AccNumber:"8765", CreatedDate:"12/12/08, } financialdata,err:=proto.Marshal(financial) iferr!=nil{ log.Fatal("marshalingerror:",err) }
userdata:=&User{ ID:"1", Email:"[email protected]", Name:"James", Mobile:"8765432", Age:"34", Financial:string(financialdata), }
userDataJSONasBytes,err:=json.Marshal(userdata)
iferr!=nil{ returnshim.Error(err.Error()) } indexName:="id" userNameIndexKey,err:=stub.CreateCompositeKey(indexName,[]string{userdata.ID})
iferr!=nil{ returnshim.Error(err.Error()) }
err=stub.PutState(userNameIndexKey,userDataJSONasBytes) iferr!=nil{ returnshim.Error(err.Error())
解析Protobuf
解析protobuf数据非常简单,因为它以字节的形式存储记录,可以使用Financialproto轻松地对其进行解析。 financialByteData,err:=proto.Marshal(financialData) iferr!=nil{ log.Fatal("marshalingerror:",err) }
//Parsingthefinancialbytedata financial:=&Financial{} err=proto.Unmarshal(financialByteData,financial) iferr!=nil{ log.Fatal("unmarshalingerror:",err) }
fmt.Println("BankName:"+financial.GetBankName()) fmt.Println("IFSCCode:"+financial.GetIfscCode()) fmt.Println("AccNumber:"+financial.GetAccNumber()) fmt.Println("CreatedDate:"+financial.GetCreatedDate()
总结
Protobuf简化了数据处理和格式化。它使用特殊生成的源代码来构造数据,从而实现在同一smartcontract中轻松写入和读取数据。 参考文献
1.https://developers.google.com/protocol-buffers 2.https://developers.google.com/protocol-buffers/docs/gotutorial 以上,就是在超级账本HyperledgerFabric中将Protobu用于到SmartContract的基本概述。 希望你能有所收获!
原文链接:https://hackernoon.com/what-is-protobuf-in-hyperledger-fabric-explained-gk7s32fz 本文为CSDN翻译,转载请注明出处。 更多精彩推荐 ?完了!CPU一味求快出事儿了!|原力计划 ?美国对华为出口管制升级;微信红包生成器App遭腾讯起诉;Python3.8.3发布|极客头条 ?潘石屹Python考试成绩99分,网友:还有一分怕你骄傲 ?发家致富靠AI?使用keras预测NBA比赛赚钱,回报率达136%…… ?看完这篇操作系统,和面试官扯皮就没问题了! ?赠书|要解决区块链的可扩展性问题,有哪些可行的方法?
你点的每个“在看”,我都认真当成了喜欢本文来源:区块链大本营 原文标题:超级账本Hyperledger Fabric中的Protobuf到底是什么?
—-
编译者/作者:区块链大本营
玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。
|