code: func (s *StandardChannel) ProcessConfigUpdateMsg(env *cb.Envelope) (config *cb.Envelope, configSeq uint64, err error) {
  	logger.Debugf("Processing config update message for channel %s", s.support.ChainID())
  
  	// Call Sequence first.  If seq advances between proposal and acceptance, this is okay, and will cause reprocessing
  	// however, if Sequence is called last, then a success could be falsely attributed to a newer configSeq
  	seq := s.support.Sequence()
  	err = s.filters.Apply(env)
  	if err != nil {
  		return nil, 0, err
  	}
  
  	configEnvelope, err := s.support.ProposeConfigUpdate(env)
  	if err != nil {
  		return nil, 0, errors.WithMessage(err, fmt.Sprintf("error applying config update to existing channel '%s'", s.support.ChainID()))
  	}
  
  	config, err = utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, s.support.ChainID(), s.support.Signer(), configEnvelope, msgVersion, epoch)
  	if err != nil {
  		return nil, 0, err
  	}
  
  	// We re-apply the filters here, especially for the size filter, to ensure that the transaction we
  	// just constructed is not too large for our consenter.  It additionally reapplies the signature
  	// check, which although not strictly necessary, is a good sanity check, in case the orderer
  	// has not been configured with the right cert material.  The additional overhead of the signature
  	// check is negligable, as this is the reconfig path and not the normal path.
  	err = s.filters.Apply(config)
  	if err != nil {
  		return nil, 0, err
  	}
  
  	return config, seq, nil
  }
docs: // ProcessConfigUpdateMsg will attempt to apply the config impetus msg to the current configuration, and if successful
  // return the resulting config message and the configSeq the config was computed from.  If the config impetus message
  // is invalid, an error is returned.