code: func validateAndPreparePvtBatch(block *internal.Block, db privacyenabledstate.DB,
  	pubAndHashUpdates *internal.PubAndHashUpdates, pvtdata map[uint64]*ledger.TxPvtData) (*privacyenabledstate.PvtUpdateBatch, error) {
  	pvtUpdates := privacyenabledstate.NewPvtUpdateBatch()
  	metadataUpdates := metadataUpdates{}
  	for _, tx := range block.Txs {
  		if tx.ValidationCode != peer.TxValidationCode_VALID {
  			continue
  		}
  		if !tx.ContainsPvtWrites() {
  			continue
  		}
  		txPvtdata := pvtdata[uint64(tx.IndexInBlock)]
  		if txPvtdata == nil {
  			continue
  		}
  		if requiresPvtdataValidation(txPvtdata) {
  			if err := validatePvtdata(tx, txPvtdata); err != nil {
  				return nil, err
  			}
  		}
  		var pvtRWSet *rwsetutil.TxPvtRwSet
  		var err error
  		if pvtRWSet, err = rwsetutil.TxPvtRwSetFromProtoMsg(txPvtdata.WriteSet); err != nil {
  			return nil, err
  		}
  		addPvtRWSetToPvtUpdateBatch(pvtRWSet, pvtUpdates, version.NewHeight(block.Num, uint64(tx.IndexInBlock)))
  		addEntriesToMetadataUpdates(metadataUpdates, pvtRWSet)
  	}
  	if err := incrementPvtdataVersionIfNeeded(metadataUpdates, pvtUpdates, pubAndHashUpdates, db); err != nil {
  		return nil, err
  	}
  	return pvtUpdates, nil
  }
docs: // validateAndPreparePvtBatch pulls out the private write-set for the transactions that are marked as valid
  // by the internal public data validator. Finally, it validates (if not already self-endorsed) the pvt rwset against the
  // corresponding hash present in the public rwset