超級賬本Hyperledger Fabric中的Protobuf到底是什麼?

買賣虛擬貨幣

作者 |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.protosyntax="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.protopackagemainimport(fmt"fmt"proto"github.com/golang/protobuf/proto"math"math")//Referenceimportstosuppresserrorsiftheyarenototherwiseused.var_=proto.Marshalvar_=fmt.Errorfvar_=math.Inf//Thisisacompile-timeassertiontoensurethatthisgeneratedfile//iscompatiblewiththeprotopackageitisbeingcompiledagainst.//Acompilationerroratthislinelikelymeansyourcopyofthe//protopackageneedstobeupdated.const_=proto.ProtoPackageIsVersion3//pleaseupgradetheprotopackagetypeFinancialstruct{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.InternalMessageInfofunc(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{//136bytesofagzippedFileDescriptorProto0x1f,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中。

packagemainimport("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資料非常簡單,因為它以位元組的形式儲存記錄,可以使用Financial proto輕鬆地對其進行解析。

financialByteData,err:=proto.Marshal(financialData)iferr!=nil{log.Fatal("marshalingerror:",err)}//Parsingthefinancialbytedatafinancial:=&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

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;