github.com/pvitto98/fabric@v2.1.1+incompatible/core/ledger/ledgerstorage/store.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package ledgerstorage
     8  
     9  import (
    10  	"sync"
    11  	"sync/atomic"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/common"
    14  	"github.com/hyperledger/fabric/common/flogging"
    15  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    16  	"github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage"
    17  	"github.com/hyperledger/fabric/common/metrics"
    18  	"github.com/hyperledger/fabric/core/ledger"
    19  	"github.com/hyperledger/fabric/core/ledger/pvtdatapolicy"
    20  	"github.com/hyperledger/fabric/core/ledger/pvtdatastorage"
    21  )
    22  
    23  const maxBlockFileSize = 64 * 1024 * 1024
    24  
    25  var logger = flogging.MustGetLogger("ledgerstorage")
    26  
    27  // Provider encapsulates two providers 1) block store provider and 2) and pvt data store provider
    28  type Provider struct {
    29  	blkStoreProvider     blkstorage.BlockStoreProvider
    30  	pvtdataStoreProvider pvtdatastorage.Provider
    31  }
    32  
    33  // Store encapsulates two stores 1) block store and pvt data store
    34  type Store struct {
    35  	blkstorage.BlockStore
    36  	pvtdataStore                pvtdatastorage.Store
    37  	rwlock                      sync.RWMutex
    38  	isPvtstoreAheadOfBlockstore atomic.Value
    39  }
    40  
    41  var attrsToIndex = []blkstorage.IndexableAttr{
    42  	blkstorage.IndexableAttrBlockHash,
    43  	blkstorage.IndexableAttrBlockNum,
    44  	blkstorage.IndexableAttrTxID,
    45  	blkstorage.IndexableAttrBlockNumTranNum,
    46  }
    47  
    48  // NewProvider returns the handle to the provider
    49  func NewProvider(blockStoreDir string, conf *pvtdatastorage.PrivateDataConfig, metricsProvider metrics.Provider) (*Provider, error) {
    50  	// Initialize the block storage
    51  	indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
    52  	blockStoreProvider, err := fsblkstorage.NewProvider(
    53  		fsblkstorage.NewConf(
    54  			blockStoreDir,
    55  			maxBlockFileSize,
    56  		),
    57  		indexConfig,
    58  		metricsProvider,
    59  	)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	pvtStoreProvider, err := pvtdatastorage.NewProvider(conf)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	return &Provider{blockStoreProvider, pvtStoreProvider}, nil
    68  }
    69  
    70  // Open opens the store
    71  func (p *Provider) Open(ledgerid string) (*Store, error) {
    72  	var blockStore blkstorage.BlockStore
    73  	var pvtdataStore pvtdatastorage.Store
    74  	var err error
    75  
    76  	if blockStore, err = p.blkStoreProvider.OpenBlockStore(ledgerid); err != nil {
    77  		return nil, err
    78  	}
    79  	if pvtdataStore, err = p.pvtdataStoreProvider.OpenStore(ledgerid); err != nil {
    80  		return nil, err
    81  	}
    82  	store := &Store{
    83  		BlockStore:   blockStore,
    84  		pvtdataStore: pvtdataStore,
    85  	}
    86  
    87  	info, err := blockStore.GetBlockchainInfo()
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	pvtstoreHeight, err := pvtdataStore.LastCommittedBlockHeight()
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	store.isPvtstoreAheadOfBlockstore.Store(pvtstoreHeight > info.Height)
    96  
    97  	return store, nil
    98  }
    99  
   100  // Close closes the provider
   101  func (p *Provider) Close() {
   102  	p.blkStoreProvider.Close()
   103  	p.pvtdataStoreProvider.Close()
   104  }
   105  
   106  // Exists checks whether the ledgerID already presents
   107  func (p *Provider) Exists(ledgerID string) (bool, error) {
   108  	return p.blkStoreProvider.Exists(ledgerID)
   109  }
   110  
   111  // Init initializes store with essential configurations
   112  func (s *Store) Init(btlPolicy pvtdatapolicy.BTLPolicy) {
   113  	s.pvtdataStore.Init(btlPolicy)
   114  }
   115  
   116  // CommitWithPvtData commits the block and the corresponding pvt data in an atomic operation
   117  func (s *Store) CommitWithPvtData(blockAndPvtdata *ledger.BlockAndPvtData) error {
   118  	blockNum := blockAndPvtdata.Block.Header.Number
   119  	s.rwlock.Lock()
   120  	defer s.rwlock.Unlock()
   121  
   122  	pvtBlkStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight()
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	if pvtBlkStoreHt < blockNum+1 { // The pvt data store sanity check does not allow rewriting the pvt data.
   128  		// when re-processing blocks (rejoin the channel or re-fetching last few block),
   129  		// skip the pvt data commit to the pvtdata blockstore
   130  		logger.Debugf("Writing block [%d] to pvt block store", blockNum)
   131  		// If a state fork occurs during a regular block commit,
   132  		// we have a mechanism to drop all blocks followed by refetching of blocks
   133  		// and re-processing them. In the current way of doing this, we only drop
   134  		// the block files (and related artifacts) but we do not drop/overwrite the
   135  		// pvtdatastorage as it might leads to data loss.
   136  		// During block reprocessing, as there is a possibility of an invalid pvtdata
   137  		// transaction to become valid, we store the pvtdata of invalid transactions
   138  		// too in the pvtdataStore as we do for the publicdata in the case of blockStore.
   139  		pvtData, missingPvtData := constructPvtDataAndMissingData(blockAndPvtdata)
   140  		if err := s.pvtdataStore.Commit(blockAndPvtdata.Block.Header.Number, pvtData, missingPvtData); err != nil {
   141  			return err
   142  		}
   143  	} else {
   144  		logger.Debugf("Skipping writing block [%d] to pvt block store as the store height is [%d]", blockNum, pvtBlkStoreHt)
   145  	}
   146  
   147  	if err := s.AddBlock(blockAndPvtdata.Block); err != nil {
   148  		return err
   149  	}
   150  
   151  	if pvtBlkStoreHt == blockNum+1 {
   152  		// we reach here only when the pvtdataStore was ahead
   153  		// of blockStore during the store opening time (would
   154  		// occur after a peer rollback/reset).
   155  		s.isPvtstoreAheadOfBlockstore.Store(false)
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  func constructPvtDataAndMissingData(blockAndPvtData *ledger.BlockAndPvtData) ([]*ledger.TxPvtData,
   162  	ledger.TxMissingPvtDataMap) {
   163  
   164  	var pvtData []*ledger.TxPvtData
   165  	missingPvtData := make(ledger.TxMissingPvtDataMap)
   166  
   167  	numTxs := uint64(len(blockAndPvtData.Block.Data.Data))
   168  
   169  	// for all tx, construct pvtdata and missing pvtdata list
   170  	for txNum := uint64(0); txNum < numTxs; txNum++ {
   171  		if pvtdata, ok := blockAndPvtData.PvtData[txNum]; ok {
   172  			pvtData = append(pvtData, pvtdata)
   173  		}
   174  
   175  		if missingData, ok := blockAndPvtData.MissingPvtData[txNum]; ok {
   176  			for _, missing := range missingData {
   177  				missingPvtData.Add(txNum, missing.Namespace,
   178  					missing.Collection, missing.IsEligible)
   179  			}
   180  		}
   181  	}
   182  	return pvtData, missingPvtData
   183  }
   184  
   185  // CommitPvtDataOfOldBlocks commits the pvtData of old blocks
   186  func (s *Store) CommitPvtDataOfOldBlocks(blocksPvtData map[uint64][]*ledger.TxPvtData) error {
   187  	err := s.pvtdataStore.CommitPvtDataOfOldBlocks(blocksPvtData)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	return nil
   192  }
   193  
   194  // GetPvtDataAndBlockByNum returns the block and the corresponding pvt data.
   195  // The pvt data is filtered by the list of 'collections' supplied
   196  func (s *Store) GetPvtDataAndBlockByNum(blockNum uint64, filter ledger.PvtNsCollFilter) (*ledger.BlockAndPvtData, error) {
   197  	s.rwlock.RLock()
   198  	defer s.rwlock.RUnlock()
   199  
   200  	var block *common.Block
   201  	var pvtdata []*ledger.TxPvtData
   202  	var err error
   203  	if block, err = s.RetrieveBlockByNumber(blockNum); err != nil {
   204  		return nil, err
   205  	}
   206  	if pvtdata, err = s.getPvtDataByNumWithoutLock(blockNum, filter); err != nil {
   207  		return nil, err
   208  	}
   209  	return &ledger.BlockAndPvtData{Block: block, PvtData: constructPvtdataMap(pvtdata)}, nil
   210  }
   211  
   212  // GetPvtDataByNum returns only the pvt data  corresponding to the given block number
   213  // The pvt data is filtered by the list of 'ns/collections' supplied in the filter
   214  // A nil filter does not filter any results
   215  func (s *Store) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
   216  	s.rwlock.RLock()
   217  	defer s.rwlock.RUnlock()
   218  	return s.getPvtDataByNumWithoutLock(blockNum, filter)
   219  }
   220  
   221  // getPvtDataByNumWithoutLock returns only the pvt data  corresponding to the given block number.
   222  // This function does not acquire a readlock and it is expected that in most of the circumstances, the caller
   223  // possesses a read lock on `s.rwlock`
   224  func (s *Store) getPvtDataByNumWithoutLock(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
   225  	var pvtdata []*ledger.TxPvtData
   226  	var err error
   227  	if pvtdata, err = s.pvtdataStore.GetPvtDataByBlockNum(blockNum, filter); err != nil {
   228  		return nil, err
   229  	}
   230  	return pvtdata, nil
   231  }
   232  
   233  // DoesPvtDataInfoExist returns true when
   234  // (1) the ledger has pvtdata associated with the given block number (or)
   235  // (2) a few or all pvtdata associated with the given block number is missing but the
   236  //     missing info is recorded in the ledger (or)
   237  // (3) the block is committed does not contain any pvtData.
   238  func (s *Store) DoesPvtDataInfoExist(blockNum uint64) (bool, error) {
   239  	pvtStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight()
   240  	if err != nil {
   241  		return false, err
   242  	}
   243  	return blockNum+1 <= pvtStoreHt, nil
   244  }
   245  
   246  // GetMissingPvtDataInfoForMostRecentBlocks invokes the function on underlying pvtdata store
   247  func (s *Store) GetMissingPvtDataInfoForMostRecentBlocks(maxBlock int) (ledger.MissingPvtDataInfo, error) {
   248  	// it is safe to not acquire a read lock on s.rwlock. Without a lock, the value of
   249  	// lastCommittedBlock can change due to a new block commit. As a result, we may not
   250  	// be able to fetch the missing data info of truly the most recent blocks. This
   251  	// decision was made to ensure that the regular block commit rate is not affected.
   252  	return s.pvtdataStore.GetMissingPvtDataInfoForMostRecentBlocks(maxBlock)
   253  }
   254  
   255  // ProcessCollsEligibilityEnabled invokes the function on underlying pvtdata store
   256  func (s *Store) ProcessCollsEligibilityEnabled(committingBlk uint64, nsCollMap map[string][]string) error {
   257  	return s.pvtdataStore.ProcessCollsEligibilityEnabled(committingBlk, nsCollMap)
   258  }
   259  
   260  // GetLastUpdatedOldBlocksPvtData invokes the function on underlying pvtdata store
   261  func (s *Store) GetLastUpdatedOldBlocksPvtData() (map[uint64][]*ledger.TxPvtData, error) {
   262  	return s.pvtdataStore.GetLastUpdatedOldBlocksPvtData()
   263  }
   264  
   265  // ResetLastUpdatedOldBlocksList invokes the function on underlying pvtdata store
   266  func (s *Store) ResetLastUpdatedOldBlocksList() error {
   267  	return s.pvtdataStore.ResetLastUpdatedOldBlocksList()
   268  }
   269  
   270  // IsPvtStoreAheadOfBlockStore returns true when the pvtStore height is
   271  // greater than the blockstore height. Otherwise, it returns false.
   272  func (s *Store) IsPvtStoreAheadOfBlockStore() bool {
   273  	return s.isPvtstoreAheadOfBlockstore.Load().(bool)
   274  }
   275  
   276  func constructPvtdataMap(pvtdata []*ledger.TxPvtData) ledger.TxPvtDataMap {
   277  	if pvtdata == nil {
   278  		return nil
   279  	}
   280  	m := make(map[uint64]*ledger.TxPvtData)
   281  	for _, pvtdatum := range pvtdata {
   282  		m[pvtdatum.SeqInBlock] = pvtdatum
   283  	}
   284  	return m
   285  }
   286  
   287  // LoadPreResetHeight returns the pre reset height for the specified ledgers.
   288  func LoadPreResetHeight(blockstorePath string, ledgerIDs []string) (map[string]uint64, error) {
   289  	return fsblkstorage.LoadPreResetHeight(blockstorePath, ledgerIDs)
   290  }
   291  
   292  // ResetBlockStore resets all ledgers to the genesis block.
   293  func ResetBlockStore(blockstorePath string) error {
   294  	return fsblkstorage.ResetBlockStore(blockstorePath)
   295  }
   296  
   297  // ValidateRollbackParams performs necessary validation on the input given for
   298  // the rollback operation.
   299  func ValidateRollbackParams(blockstorePath, ledgerID string, blockNum uint64) error {
   300  	return fsblkstorage.ValidateRollbackParams(blockstorePath, ledgerID, blockNum)
   301  }
   302  
   303  // Rollback reverts changes made to the block store beyond a given block number.
   304  func Rollback(blockstorePath, ledgerID string, blockNum uint64) error {
   305  	indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
   306  	return fsblkstorage.Rollback(blockstorePath, ledgerID, blockNum, indexConfig)
   307  }