github.com/true-sqn/fabric@v2.1.1+incompatible/protoutil/blockutils.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package protoutil
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/sha256"
    12  	"encoding/asn1"
    13  	"math/big"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	cb "github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // NewBlock constructs a block with no data and no metadata.
    21  func NewBlock(seqNum uint64, previousHash []byte) *cb.Block {
    22  	block := &cb.Block{}
    23  	block.Header = &cb.BlockHeader{}
    24  	block.Header.Number = seqNum
    25  	block.Header.PreviousHash = previousHash
    26  	block.Header.DataHash = []byte{}
    27  	block.Data = &cb.BlockData{}
    28  
    29  	var metadataContents [][]byte
    30  	for i := 0; i < len(cb.BlockMetadataIndex_name); i++ {
    31  		metadataContents = append(metadataContents, []byte{})
    32  	}
    33  	block.Metadata = &cb.BlockMetadata{Metadata: metadataContents}
    34  
    35  	return block
    36  }
    37  
    38  type asn1Header struct {
    39  	Number       *big.Int
    40  	PreviousHash []byte
    41  	DataHash     []byte
    42  }
    43  
    44  func BlockHeaderBytes(b *cb.BlockHeader) []byte {
    45  	asn1Header := asn1Header{
    46  		PreviousHash: b.PreviousHash,
    47  		DataHash:     b.DataHash,
    48  		Number:       new(big.Int).SetUint64(b.Number),
    49  	}
    50  	result, err := asn1.Marshal(asn1Header)
    51  	if err != nil {
    52  		// Errors should only arise for types which cannot be encoded, since the
    53  		// BlockHeader type is known a-priori to contain only encodable types, an
    54  		// error here is fatal and should not be propogated
    55  		panic(err)
    56  	}
    57  	return result
    58  }
    59  
    60  func BlockHeaderHash(b *cb.BlockHeader) []byte {
    61  	sum := sha256.Sum256(BlockHeaderBytes(b))
    62  	return sum[:]
    63  }
    64  
    65  func BlockDataHash(b *cb.BlockData) []byte {
    66  	sum := sha256.Sum256(bytes.Join(b.Data, nil))
    67  	return sum[:]
    68  }
    69  
    70  // GetChainIDFromBlockBytes returns chain ID given byte array which represents
    71  // the block
    72  func GetChainIDFromBlockBytes(bytes []byte) (string, error) {
    73  	block, err := UnmarshalBlock(bytes)
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  
    78  	return GetChainIDFromBlock(block)
    79  }
    80  
    81  // GetChainIDFromBlock returns chain ID in the block
    82  func GetChainIDFromBlock(block *cb.Block) (string, error) {
    83  	if block == nil || block.Data == nil || block.Data.Data == nil || len(block.Data.Data) == 0 {
    84  		return "", errors.New("failed to retrieve channel id - block is empty")
    85  	}
    86  	var err error
    87  	envelope, err := GetEnvelopeFromBlock(block.Data.Data[0])
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  	payload, err := UnmarshalPayload(envelope.Payload)
    92  	if err != nil {
    93  		return "", err
    94  	}
    95  
    96  	if payload.Header == nil {
    97  		return "", errors.New("failed to retrieve channel id - payload header is empty")
    98  	}
    99  	chdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader)
   100  	if err != nil {
   101  		return "", err
   102  	}
   103  
   104  	return chdr.ChannelId, nil
   105  }
   106  
   107  // GetMetadataFromBlock retrieves metadata at the specified index.
   108  func GetMetadataFromBlock(block *cb.Block, index cb.BlockMetadataIndex) (*cb.Metadata, error) {
   109  	if block.Metadata == nil {
   110  		return nil, errors.New("no metadata in block")
   111  	}
   112  
   113  	if len(block.Metadata.Metadata) <= int(index) {
   114  		return nil, errors.Errorf("no metadata at index [%s]", index)
   115  	}
   116  
   117  	md := &cb.Metadata{}
   118  	err := proto.Unmarshal(block.Metadata.Metadata[index], md)
   119  	if err != nil {
   120  		return nil, errors.Wrapf(err, "error unmarshaling metadata at index [%s]", index)
   121  	}
   122  	return md, nil
   123  }
   124  
   125  // GetMetadataFromBlockOrPanic retrieves metadata at the specified index, or
   126  // panics on error
   127  func GetMetadataFromBlockOrPanic(block *cb.Block, index cb.BlockMetadataIndex) *cb.Metadata {
   128  	md, err := GetMetadataFromBlock(block, index)
   129  	if err != nil {
   130  		panic(err)
   131  	}
   132  	return md
   133  }
   134  
   135  // GetConsenterMetadataFromBlock attempts to retrieve consenter metadata from the value
   136  // stored in block metadata at index SIGNATURES (first field). If no consenter metadata
   137  // is found there, it falls back to index ORDERER (third field).
   138  func GetConsenterMetadataFromBlock(block *cb.Block) (*cb.Metadata, error) {
   139  	m, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)
   140  	if err != nil {
   141  		return nil, errors.WithMessage(err, "failed to retrieve metadata")
   142  	}
   143  
   144  	// TODO FAB-15864 Remove this fallback when we can stop supporting upgrade from pre-1.4.1 orderer
   145  	if len(m.Value) == 0 {
   146  		return GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER)
   147  	}
   148  
   149  	obm := &cb.OrdererBlockMetadata{}
   150  	err = proto.Unmarshal(m.Value, obm)
   151  	if err != nil {
   152  		return nil, errors.Wrap(err, "failed to unmarshal orderer block metadata")
   153  	}
   154  
   155  	res := &cb.Metadata{}
   156  	err = proto.Unmarshal(obm.ConsenterMetadata, res)
   157  	if err != nil {
   158  		return nil, errors.Wrap(err, "failed to unmarshal consenter metadata")
   159  	}
   160  
   161  	return res, nil
   162  }
   163  
   164  // GetLastConfigIndexFromBlock retrieves the index of the last config block as
   165  // encoded in the block metadata
   166  func GetLastConfigIndexFromBlock(block *cb.Block) (uint64, error) {
   167  	m, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)
   168  	if err != nil {
   169  		return 0, errors.WithMessage(err, "failed to retrieve metadata")
   170  	}
   171  	// TODO FAB-15864 Remove this fallback when we can stop supporting upgrade from pre-1.4.1 orderer
   172  	if len(m.Value) == 0 {
   173  		m, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG)
   174  		if err != nil {
   175  			return 0, errors.WithMessage(err, "failed to retrieve metadata")
   176  		}
   177  		lc := &cb.LastConfig{}
   178  		err = proto.Unmarshal(m.Value, lc)
   179  		if err != nil {
   180  			return 0, errors.Wrap(err, "error unmarshaling LastConfig")
   181  		}
   182  		return lc.Index, nil
   183  	}
   184  
   185  	obm := &cb.OrdererBlockMetadata{}
   186  	err = proto.Unmarshal(m.Value, obm)
   187  	if err != nil {
   188  		return 0, errors.Wrap(err, "failed to unmarshal orderer block metadata")
   189  	}
   190  	return obm.LastConfig.Index, nil
   191  }
   192  
   193  // GetLastConfigIndexFromBlockOrPanic retrieves the index of the last config
   194  // block as encoded in the block metadata, or panics on error
   195  func GetLastConfigIndexFromBlockOrPanic(block *cb.Block) uint64 {
   196  	index, err := GetLastConfigIndexFromBlock(block)
   197  	if err != nil {
   198  		panic(err)
   199  	}
   200  	return index
   201  }
   202  
   203  // CopyBlockMetadata copies metadata from one block into another
   204  func CopyBlockMetadata(src *cb.Block, dst *cb.Block) {
   205  	dst.Metadata = src.Metadata
   206  	// Once copied initialize with rest of the
   207  	// required metadata positions.
   208  	InitBlockMetadata(dst)
   209  }
   210  
   211  // InitBlockMetadata initializes metadata structure
   212  func InitBlockMetadata(block *cb.Block) {
   213  	if block.Metadata == nil {
   214  		block.Metadata = &cb.BlockMetadata{Metadata: [][]byte{{}, {}, {}, {}, {}}}
   215  	} else if len(block.Metadata.Metadata) < int(cb.BlockMetadataIndex_COMMIT_HASH+1) {
   216  		for i := int(len(block.Metadata.Metadata)); i <= int(cb.BlockMetadataIndex_COMMIT_HASH); i++ {
   217  			block.Metadata.Metadata = append(block.Metadata.Metadata, []byte{})
   218  		}
   219  	}
   220  }