code: func (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
  	getState := &pb.GetState{}
  	err := proto.Unmarshal(msg.Payload, getState)
  	if err != nil {
  		return nil, errors.Wrap(err, "unmarshal failed")
  	}
  
  	var res []byte
  	chaincodeName := h.ChaincodeName()
  	collection := getState.Collection
  	chaincodeLogger.Debugf("[%s] getting state for chaincode %s, key %s, channel %s", shorttxid(msg.Txid), chaincodeName, getState.Key, txContext.ChainID)
  
  	if isCollectionSet(collection) {
  		if txContext.IsInitTransaction {
  			return nil, errors.New("private data APIs are not allowed in chaincode Init()")
  		}
  		if err := errorIfCreatorHasNoReadAccess(chaincodeName, collection, txContext); err != nil {
  			return nil, err
  		}
  		res, err = txContext.TXSimulator.GetPrivateData(chaincodeName, collection, getState.Key)
  	} else {
  		res, err = txContext.TXSimulator.GetState(chaincodeName, getState.Key)
  	}
  	if err != nil {
  		return nil, errors.WithStack(err)
  	}
  	if res == nil {
  		chaincodeLogger.Debugf("[%s] No state associated with key: %s. Sending %s with an empty payload", shorttxid(msg.Txid), getState.Key, pb.ChaincodeMessage_RESPONSE)
  	}
  
  	// Send response msg back to chaincode. GetState will not trigger event
  	return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: res, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
  }
docs: // Handles query to ledger to get state