code: func validateChaincodeProposalMessage(prop *pb.Proposal, hdr *common.Header) (*pb.ChaincodeHeaderExtension, error) {
  	if prop == nil || hdr == nil {
  		return nil, errors.New("nil arguments")
  	}
  
  	putilsLogger.Debugf("validateChaincodeProposalMessage starts for proposal %p, header %p", prop, hdr)
  
  	// 4) based on the header type (assuming it's CHAINCODE), look at the extensions
  	chaincodeHdrExt, err := utils.GetChaincodeHeaderExtension(hdr)
  	if err != nil {
  		return nil, errors.New("invalid header extension for type CHAINCODE")
  	}
  
  	if chaincodeHdrExt.ChaincodeId == nil {
  		return nil, errors.New("ChaincodeHeaderExtension.ChaincodeId is nil")
  	}
  
  	putilsLogger.Debugf("validateChaincodeProposalMessage info: header extension references chaincode %s", chaincodeHdrExt.ChaincodeId)
  
  	//    - ensure that the chaincodeID is correct (?)
  	// TODO: should we even do this? If so, using which interface?
  
  	//    - ensure that the visibility field has some value we understand
  	// currently the fabric only supports full visibility: this means that
  	// there are no restrictions on which parts of the proposal payload will
  	// be visible in the final transaction; this default approach requires
  	// no additional instructions in the PayloadVisibility field which is
  	// therefore expected to be nil; however the fabric may be extended to
  	// encode more elaborate visibility mechanisms that shall be encoded in
  	// this field (and handled appropriately by the peer)
  	if chaincodeHdrExt.PayloadVisibility != nil {
  		return nil, errors.New("invalid payload visibility field")
  	}
  
  	return chaincodeHdrExt, nil
  }
docs: // validateChaincodeProposalMessage checks the validity of a Proposal message of type CHAINCODE