In this article, I’ll explain the technique used in serializing structured data using Protobuf in Hyperledger Fabric. Protobuf makes simpler in data processing and formatting. It structures the data with specially generated source code to easily write and read data within the same smartcontract. Chaincode and SmartContract In hyperledger fabric, is a specific program that handles the core business logic agreed by the group of participants in a blockchain network. Hyperledger fabric also uses a data format technique called defined for a specific set of a data model within a . Chaincode can have multiple sets of to work as a transaction logic that controls the different data models. In simple words, governs the transactions, whereas governs how smartcontract are packaged for deployment. Chaincode SmartContract Chaincode SmartContract SmartContract Chaincode Example: If a few user records need to be stored into the ledger then we need to have a SmartContract defining all required data fields of a single User SmartContract User { ID Email Name Mobile Age } type struct string `json:"id"` string `json:"email"` string `json:"name"` string `json:"mobile"` string `json:"age"` In this SmartContract, there are ID, Email, Name, Mobile, Age data fields relates to a single user record. Similarly, if we need to store the financial records for each user then we will have another smartcontract called Financial . Financial SmartContract Financial { ID BankName IFSCCode AccNumber CreatedDate } type struct string `json:"id"` string `json:"bankName"` string `json:"ifscCode"` string `json:"accNumber"` string `json:"createdDate"` So, these two smartcontracts will be deployed into the . And will handle the transaction logic for both ledger state — . SmartContract mainly performs in the world state. 1. Chaincode WorldState , Blockchain Put, Get, Delete and GetHistory PutState — It creates new objects per distinct key or will overwrite to the existing objects. 2. 3. 4. All the records are stored in the as a world state record. The objects are stored as pair in data format. CouchDB is faster in querying JSON collections from the database. In , all these records are stored in the byte and it’s immutable. GetState — It retrieves the object for a distinct key from the ledger state. DelState — It removes the object from the world state of the ledger. GetHistoryForKey — Returns all the transaction history records for a key across time. CouchDB key-value JSON Blockchain state Protobuf Protocol buffer (short as ) is serializing structured data with the language-neutral, platform-neutral, extensible mechanism. The serialize structured data is compiled in bytes and smaller, faster, simpler compared to traditional data formats like or . protobuf Google’s XML JSON Why use Protobuf? As we have seen, there is two smartcontracts and to store the information into the ledger of the same user, which means stores the basic bio information and stores the banking details of the user. User Financial User Financial But, if we look into the smartcontracts in terms of querying purpose there is no relation among two data collection. We cannot define the same as key for and data model because ledger data stores in pair and for the same key the information will be overridden. ID User Financial key-value Both records will be stored with two different IDs in the ledger state To solve this problem, provides a faster and flexible solution. We just need to write a file describing the data structure, in this case, the data structure we want to store. Protobuf .proto Financial So, the byte result of the message format invokes directly to the and removing completely. protobuf User SmartContract Financial SmartContract How Protobuf works? We will see here, how to setup compiler and generating protobuf message format. protobuf Installation First, we need to follow a few installation processes to use . protobuf-compiler $ go get github.com/golang/protobuf $ go get github.com/golang/protobuf/proto $ go get -u github.com/golang/protobuf/protoc-gen-go $ PATH= : /bin export $PATH $GOPATH Now, install the protobuf-compiler $ sudo apt install protobuf-compiler Now, type protoc ’ in the command line. It should say ‘ Missing input file ’, which means the protobuf-compiler is successfully installed. Example First, we need to create a file. It consists of a message format of type , which has four fields, . financial.proto Financial bank name, ifsc code, account number, created date financial.proto syntax= ; main; message Financial { bankName = ; ifscCode = ; accNumber = ; createdDate = ; } "proto3" package string 1 string 2 string 3 string 4 Compile the file to generate the protobuf data model file for message format. proto Financial $ protoc --go_out=. *.proto You can see a file has generated as . This file is a compatibility data model with the proto package and it will be used to convert the proto message format into bytes. protobuf financial.pb.go financial.pb.go main ( fmt proto math ) _ = proto.Marshal _ = fmt.Errorf _ = math.Inf _ = proto.ProtoPackageIsVersion3 Financial { BankName IfscCode AccNumber CreatedDate XXX_NoUnkeyedLiteral {} XXX_unrecognized [] XXX_sizecache } { *m = Financial{} } { proto.CompactTextString(m) } {} { fileDescriptor_a283ebe7677acfbc, [] { } } { xxx_messageInfo_Financial.Unmarshal(m, b) } { xxx_messageInfo_Financial.Marshal(b, m, deterministic) } { xxx_messageInfo_Financial.Merge(m, src) } { xxx_messageInfo_Financial.Size(m) } { xxx_messageInfo_Financial.DiscardUnknown(m) } xxx_messageInfo_Financial proto.InternalMessageInfo { m != { m.BankName } } { m != { m.IfscCode } } { m != { m.AccNumber } } { m != { m.CreatedDate } } { proto.RegisterType((*Financial)( ), ) } { proto.RegisterFile( , fileDescriptor_a283ebe7677acfbc) } fileDescriptor_a283ebe7677acfbc = [] { , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , } // Code generated by protoc-gen-go. DO NOT EDIT. // source: financial.proto package import "fmt" "github.com/golang/protobuf/proto" "math" // Reference imports to suppress errors if they are not otherwise used. var var var // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. const // please upgrade the proto package type struct string `protobuf:"bytes,1,opt,name=bankName,proto3" json:"bankName,omitempty"` string `protobuf:"bytes,2,opt,name=ifscCode,proto3" json:"ifscCode,omitempty"` string `protobuf:"bytes,3,opt,name=accNumber,proto3" json:"accNumber,omitempty"` string `protobuf:"bytes,4,opt,name=createdDate,proto3" json:"createdDate,omitempty"` struct `json:"-"` byte `json:"-"` int32 `json:"-"` func (m *Financial) Reset () func (m *Financial) String () string return func (*Financial) ProtoMessage () func (*Financial) Descriptor () ([] , [] ) byte int return int 0 func (m *Financial) XXX_Unmarshal (b [] ) byte error return func (m *Financial) XXX_Marshal (b [] , deterministic ) byte bool ([] , error) byte return func (m *Financial) XXX_Merge (src proto.Message) func (m *Financial) XXX_Size () int return func (m *Financial) XXX_DiscardUnknown () var func (m *Financial) GetBankName () string if nil return return "" func (m *Financial) GetIfscCode () string if nil return return "" func (m *Financial) GetAccNumber () string if nil return return "" func (m *Financial) GetCreatedDate () string if nil return return "" func init () nil "main.Financial" func init () "financial.proto" var byte // 136 bytes of a gzipped FileDescriptorProto 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 0x00 0x00 Now, we will create an extra data field in the . financial User smartcontract User { ID Email Name Mobile Age Financial } type struct string `json:"id"` string `json:"email"` string `json:"name"` string `json:"mobile"` string `json:"age"` string `json:"financial"` Financial message format reference financial := &Financial { ID: , BankName: , IFSCCode: , AccNumber: , CreatedDate : "F1" "Hellenic Bank" "1234" "8765" "12/12/08, } While adding the user records into the ledger, you can also add reference into the same smartcontract. financial message format User main ( ) { financial := &Financial { BankName: , IFSCCode: , AccNumber: , CreatedDate : marshaling error: james@example.com James id package import "fmt" "log" "github.com/golang/protobuf/proto" func main () "Hellenic Bank" "1234" "8765" "12/12/08, } financialdata, err := proto.Marshal(financial) if err != nil { log.Fatal(" ", err) } userdata := &User { ID: " 1 ", Email: " ", Name: " ", Mobile: " 8765432 ", Age: " 34 ", Financial: string(financialdata), } userDataJSONasBytes, err := json.Marshal(userdata) if err != nil { return shim.Error(err.Error()) } indexName := " " userNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{userdata.ID}) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(userNameIndexKey, userDataJSONasBytes) if err != nil { return shim.Error(err.Error()) } } Parsing Protobuf Parsing data is very simple, as it stores the record in bytes, it can easily be unmarshal using the proto reference. protobuf Financial financialByteData, err := proto.Marshal(financialData) err != { log.Fatal( , err) } financial := &Financial{} err = proto.Unmarshal(financialByteData, financial) err != { log.Fatal( , err) } fmt.Println( +financial.GetBankName()) fmt.Println( +financial.GetIfscCode()) fmt.Println( +financial.GetAccNumber()) fmt.Println( +financial.GetCreatedDate()) if nil "marshaling error: " //Parsing the financial byte data if nil "unmarshaling error: " "BankName : " "IFSCCode : " "AccNumber : " "CreatedDate : " Conclusion Protobuf makes simpler in data processing and formatting. It structures the data with specially generated source code to easily write and read data within the same smartcontract. 1. References https://developers.google.com/protocol-buffers 2. So, this is the basic overview of implementing into a in Hyperledger Fabric. https://developers.google.com/protocol-buffers/docs/gotutorial Protobuf SmartContract I hope you find this article useful :-) Thanks