What’s inside the Block in Hyperledger Fabric?

What’s inside the Block in Hyperledger Fabric?

Deeptiman Pattnaik's photo
Deeptiman Pattnaik
·Jan 19, 2020·

5 min read

Subscribe to my newsletter and never miss my upcoming articles

In this article, I’ll try to demonstrate a BlockReader application written Go programming language that extracts the various segments of a block structure in Hyperledger Fabric.


BlockReader application extract and showcase the complete data structure of a Block that contains several transactions. The application will require a transaction id to query the ledger to retrieve the associated block. Then the application will follow the Block data structure to read the content of the Block.


What’s inside the Block

There are three sections of a Block that store transaction information in the ledger.

type Block struct {
      Header   *BlockHeader   
      Data     *BlockData     
      Metadata *BlockMetadata 


The header consist of Block number, copy of the previous block hash and the current block hash

type BlockHeader struct {
      Number         uint64
      PreviousHash    []byte
      DataHash        []byte


The Data fields of a block are the essentials segment that contents the transaction details sorted in the byte array. We’ll extract hidden elements of the Data byte array in the course of this article.

type BlockData struct {
     Data [][]byte 


The MetaData fields contain the created time of the block, certificate details and signature of the block writer.

type BlockMetadata struct {
  Metadata   [][]byte


The transaction is stored inside the envelope containing the transaction payload and sorted by the Ordering Service. The extraction process starts from the Envelope struct.

type Envelope struct {
     Payload   []byte 
     Signature []byte

Get Envelope from BlockData

func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error){

  var err error
  env := &common.Envelope{}
  if err = proto.Unmarshal(data, env); err != nil {
    return nil, errors.Wrap(err, "error unmarshaling Envelope")

  return env, nil


The Payload struct contains the ChannelHeader and SignatureHeader as Header fields.

type Payload struct {
     Header *Header 
     Data   []byte 

Get Payload from Envelope

payload := &common.Payload{}
err = proto.Unmarshal(envelope.Payload, payload)
if err != nil {
   return errors.WithMessage(err,"unmarshaling Payload error: ")

Payload Header

ChannelHeader It contains the basic channel information and chaincode info.

type ChannelHeader struct {
   Type      int32
   Version   int32 
   Timestamp *google_protobuf.Timestamp 
   ChannelId string 
   TxId      string 
   Epoch     uint64 
   Extension []byte 


Type: It denotes the transaction type used. ["MESSAGE", "CONFIG", "CONFIG_UPDATE", "ENDORSER_TRANSACTION",

Version: The version number for protobuf used for serialization/de-serialization of the structures.

ChannelId: Channel name for the network

TxId: The transaction id for processing the transaction

Epoch: The fields are currently unused.

Extension: It contents Chaincode information that marshalled the ChaincodeHeaderExtension structure.


Get the ChannelHeader from the Payload

channelHeader := &common.ChannelHeader{}
err := proto.Unmarshal(payload.Header.ChannelHeader, channelHeader)
if err != nil {
  return ChannelHeader{}, errors.WithMessage(err,"unmarshaling Channel Header error: ")

SignatureHeader This structure contains the Creator details that holds Mspid, identity certificate for the member service provider. The Creator field is the marshalled object of msp.SerializedIdentity.

type SignatureHeader struct {
   Creator []byte
   Nonce   []byte
signatureHeader := &common.SignatureHeader{}
err := proto.Unmarshal(payload.Header.SignatureHeader, signatureHeader)
if err != nil {
   return SignatureHeader{}, errors.WithMessage(err,"unmarshaling Signature Header error: ")

Get SignatureHeader from the Payload

signatureHeader := &common.SignatureHeader{}
err := proto.Unmarshal(payload.Header.SignatureHeader, signatureHeader)
if err != nil {
   return SignatureHeader{}, errors.WithMessage(err,"unmarshaling Signature Header error: ")

Get Creator from SignatureHeader

type SerializedIdentity struct {
   Mspid   string
   IdBytes []byte 

creator := &msp.SerializedIdentity{}
err = proto.Unmarshal(signatureHeader.Creator, creator)
if err != nil {
   return SignatureHeader{}, errors.WithMessage(err,"unmarshaling Creator error: ")

Extracting Identity Certificate for the MSP

uEnc := base64.URLEncoding.EncodeToString([]byte(creator.IdBytes))

  certText, err := base64.URLEncoding.DecodeString(uEnc)
  if err != nil {
    return SignatureHeader{}, errors.WithMessage(err,"Error decoding string: ")

  end, _ := pem.Decode([]byte(string(certText)))
  if end == nil {
    return SignatureHeader{}, errors.New("Error Pem decoding: ")
  cert, err := x509.ParseCertificate(end.Bytes)
  if err != nil {
    return SignatureHeader{}, errors.New("failed to parse certificate:: ")

  certificateJson :=  Certificate{
    Country:    cert.Issuer.Country,
    Organization:    cert.Issuer.Organization,
    OrganizationalUnit:  cert.Issuer.OrganizationalUnit,
    Locality:    cert.Issuer.Locality,
    Province:    cert.Issuer.Province,
    SerialNumber:    cert.Issuer.SerialNumber,
    NotBefore:    cert.NotBefore,
    NotAfter:    cert.NotAfter,                

Payload Data

The Data field of the Payload contains the transaction details for the Block. And the TransactionAction structure holds Header and Payload that follows Signature Header for the submitted transaction and ChainCodeActionPayload containing the Chaincode invoked arguments, type of chaincode and the read/write set for the ChaincodeEndorseTransaction.


type TransactionAction struct {
    Header  []byte 
    Payload []byte 

Header: It’s similar to the earlier SignatureHeader containing the identities details for submitting the transaction. Payload: It is the Marshalled object of ChainCodeActionPayload that contains various Chaincode actions performed during a transaction.



It contains the Chaincode Input elements used during the transaction

type ChaincodeProposalPayload struct {
   Input    []byte
   TransientMap map[string][]byte

Input: It is the marshalled object of ChaincodeInvocationSpec TransientMap: It’s content quite sensitive data related to application-level confidentiality. The details are always removed from the transaction and never gets updated in the ledger.


It contents the chaincode information and the arguments used during the invocation.

type ChaincodeInvocationSpec struct {
     ChaincodeSpec  *ChaincodeSpec
type ChaincodeSpec struct {
     Type     ChaincodeSpec_Type 
     ChaincodeId *ChaincodeID
     Input       *ChaincodeInput
     Timeout     int32
type ChaincodeInput struct {
     Args        [][]byte
     Decorations map[string][]byte


It is the marshalled object of ChaincodeEndorsedAction struct that content the Proposal Hash and the Read/Write set used for the Chaincode in the transaction.

type ChaincodeEndorsedAction struct {
     ProposalResponsePayload []byte
     Endorsements  []*Endorsement

type ProposalResponsePayload struct {
     ProposalHash []byte
     Extension    []byte   

Read/Write Set

The **Extension* field is the marshalled object of ChaincodeAction* that contains the Read and Write operation set performed for the transaction.

type ChaincodeAction struct {
     Results  []byte 
     Events   []byte 
     Response *Response 

Results: It’s the marshalled object of TxReadWriteSet struct that contains read/write set, Block Range info and the metadata.

type KVRWSet struct {
  Reads            []*KVRead         
  RangeQueriesInfo []*RangeQueryInfo 
  Writes           []*KVWrite  
  MetadataWrites   []*KVMetadataWrite      

type KVRead struct {
  Key     string   
  Version *Version 

type Version struct {
  BlockNum uint64 
  TxNum    uint64 

type KVWrite struct {
  Key      string 
  IsDelete bool   
  Value    []byte 

type RangeQueryInfo struct {
  StartKey     string 
  EndKey       string 
  ItrExhausted bool   
  ReadsInfo isRangeQueryInfo_ReadsInfo 

type KVMetadataWrite struct {
  Key      string
  Entries  []*KVMetadataEntry

type KVMetadataEntry struct {
  Name     string
  Value    []byte

So, this is the overview of extracting the Block data structure for a transaction id and understanding the core elements use cases. Please check the BlockReader application at Github and share your feedback.

I hope you find this article useful :)


Share this