头条|贵比特:超级账本Hyperledger Fabric中的Protobuf到底是什么?
摘要:作者 |Deeptiman Pattnaik译者 | 火火酱,责编 | Carol出品 | 区块链大本营在本文中,我将解

作者 |Deeptiman Pattnaik译者 | 火火酱,责编 | Carol出品 | 区块链大本营(blockchain_camp)
在本文中,我将解释如何在超账本Hyperledger Fabric中使用Protobuf对数据进行序列化和结构化。Protobuf简化了Hyperledger Fabric中数据处理和格式化过程。它使用特殊生成的源代码产生数据,从而在同一个智能合约中轻松地写入和读取数据。

Chaincode和SmartContract
在hyperledger fabric中,Chaincode(链码)是一个特定的程序,被用于处理由区块链网络的参与者所同意的核心业务逻辑。Hyperledger fabric还使用了一种名为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消息格式的字节结果直接调用到User SmartContract并完全删除Financial SmartContract。

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’。应该会显示‘Missing input file’(缺少输入文件),这表示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
现在,我们将在User smartcontract中创建一个额外的数据字段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消息格式添加到相同的User smartcontract中。
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:"james@example.com",
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
以上,就是在超级账本Hyperledger Fabric中将Protobu用于到SmartContract的基本概述。
希望你能有所收获!
原文链接:https://hackernoon.com/what-is-protobuf-in-hyperledger-fabric-explained-gk7s32fz
本文为 CSDN 翻译,转载请注明出处。
- 免责声明
- 世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
- 风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
- 世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。

币圈观察



