code: func (m *Mgr) HandleChaincodeDeploy(chainid string, chaincodeDefinitions []*ChaincodeDefinition) error {
  	logger.Debugf("Channel [%s]: Handling chaincode deploy event for chaincode [%s]", chainid, chaincodeDefinitions)
  	// Read lock to allow concurrent deploy on multiple channels but to synchronize concurrent `chaincode install` operation
  	m.rwlock.RLock()
  	for _, chaincodeDefinition := range chaincodeDefinitions {
  		installed, dbArtifacts, err := m.infoProvider.RetrieveChaincodeArtifacts(chaincodeDefinition)
  		if err != nil {
  			return err
  		}
  		if !installed {
  			logger.Infof("Channel [%s]: Chaincode [%s] is not installed hence no need to create chaincode artifacts for endorsement",
  				chainid, chaincodeDefinition)
  			continue
  		}
  		m.callbackStatus.setDeployPending(chainid)
  		if err := m.invokeHandler(chainid, chaincodeDefinition, dbArtifacts); err != nil {
  			logger.Warningf("Channel [%s]: Error while invoking a listener for handling chaincode install event: %s", chainid, err)
  			return err
  		}
  		logger.Debugf("Channel [%s]: Handled chaincode deploy event for chaincode [%s]", chainid, chaincodeDefinitions)
  	}
  	return nil
  }
docs: // HandleChaincodeDeploy is expected to be invoked when a chaincode is deployed via a deploy transaction
  // The `chaincodeDefinitions` parameter contains all the chaincodes deployed in a block
  // We need to store the last received `chaincodeDefinitions` because this function is expected to be invoked
  // after the deploy transactions validation is performed but not committed yet to the ledger. Further, we
  // release the read lock after this function. This leaves a small window when a `chaincode install` can happen
  // before the deploy transaction is committed and hence the function `HandleChaincodeInstall` may miss finding
  // the deployed chaincode. So, in function `HandleChaincodeInstall`, we explicitly check for chaincode deployed
  // in this stored `chaincodeDefinitions`