github.com/kaituanwang/hyperledger@v2.0.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  	if err := store.init(); err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	info, err := blockStore.GetBlockchainInfo()
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	pvtstoreHeight, err := pvtdataStore.LastCommittedBlockHeight()
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	store.isPvtstoreAheadOfBlockstore.Store(pvtstoreHeight > info.Height)
    99  
   100  	return store, nil
   101  }
   102  
   103  // Close closes the provider
   104  func (p *Provider) Close() {
   105  	p.blkStoreProvider.Close()
   106  	p.pvtdataStoreProvider.Close()
   107  }
   108  
   109  // Exists checks whether the ledgerID already presents
   110  func (p *Provider) Exists(ledgerID string) (bool, error) {
   111  	return p.blkStoreProvider.Exists(ledgerID)
   112  }
   113  
   114  // Init initializes store with essential configurations
   115  func (s *Store) Init(btlPolicy pvtdatapolicy.BTLPolicy) {
   116  	s.pvtdataStore.Init(btlPolicy)
   117  }
   118  
   119  // CommitWithPvtData commits the block and the corresponding pvt data in an atomic operation
   120  func (s *Store) CommitWithPvtData(blockAndPvtdata *ledger.BlockAndPvtData) error {
   121  	blockNum := blockAndPvtdata.Block.Header.Number
   122  	s.rwlock.Lock()
   123  	defer s.rwlock.Unlock()
   124  
   125  	pvtBlkStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight()
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	if pvtBlkStoreHt < blockNum+1 { // The pvt data store sanity check does not allow rewriting the pvt data.
   131  		// when re-processing blocks (rejoin the channel or re-fetching last few block),
   132  		// skip the pvt data commit to the pvtdata blockstore
   133  		logger.Debugf("Writing block [%d] to pvt block store", blockNum)
   134  		// If a state fork occurs during a regular block commit,
   135  		// we have a mechanism to drop all blocks followed by refetching of blocks
   136  		// and re-processing them. In the current way of doing this, we only drop
   137  		// the block files (and related artifacts) but we do not drop/overwrite the
   138  		// pvtdatastorage as it might leads to data loss.
   139  		// During block reprocessing, as there is a possibility of an invalid pvtdata
   140  		// transaction to become valid, we store the pvtdata of invalid transactions
   141  		// too in the pvtdataStore as we do for the publicdata in the case of blockStore.
   142  		pvtData, missingPvtData := constructPvtDataAndMissingData(blockAndPvtdata)
   143  		if err := s.pvtdataStore.Commit(blockAndPvtdata.Block.Header.Number, pvtData, missingPvtData); err != nil {
   144  			return err
   145  		}
   146  	} else {
   147  		logger.Debugf("Skipping writing block [%d] to pvt block store as the store height is [%d]", blockNum, pvtBlkStoreHt)
   148  	}
   149  
   150  	if err := s.AddBlock(blockAndPvtdata.Block); err != nil {
   151  		return err
   152  	}
   153  
   154  	if pvtBlkStoreHt == blockNum+1 {
   155  		// we reach here only when the pvtdataStore was ahead
   156  		// of blockStore during the store opening time (would
   157  		// occur after a peer rollback/reset).
   158  		s.isPvtstoreAheadOfBlockstore.Store(false)
   159  	}
   160  
   161  	return nil
   162  }
   163  
   164  func constructPvtDataAndMissingData(blockAndPvtData *ledger.BlockAndPvtData) ([]*ledger.TxPvtData,
   165  	ledger.TxMissingPvtDataMap) {
   166  
   167  	var pvtData []*ledger.TxPvtData
   168  	missingPvtData := make(ledger.TxMissingPvtDataMap)
   169  
   170  	numTxs := uint64(len(blockAndPvtData.Block.Data.Data))
   171  
   172  	// for all tx, construct pvtdata and missing pvtdata list
   173  	for txNum := uint64(0); txNum < numTxs; txNum++ {
   174  		if pvtdata, ok := blockAndPvtData.PvtData[txNum]; ok {
   175  			pvtData = append(pvtData, pvtdata)
   176  		}
   177  
   178  		if missingData, ok := blockAndPvtData.MissingPvtData[txNum]; ok {
   179  			for _, missing := range missingData {
   180  				missingPvtData.Add(txNum, missing.Namespace,
   181  					missing.Collection, missing.IsEligible)
   182  			}
   183  		}
   184  	}
   185  	return pvtData, missingPvtData
   186  }
   187  
   188  // CommitPvtDataOfOldBlocks commits the pvtData of old blocks
   189  func (s *Store) CommitPvtDataOfOldBlocks(blocksPvtData map[uint64][]*ledger.TxPvtData) error {
   190  	err := s.pvtdataStore.CommitPvtDataOfOldBlocks(blocksPvtData)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	return nil
   195  }
   196  
   197  // GetPvtDataAndBlockByNum returns the block and the corresponding pvt data.
   198  // The pvt data is filtered by the list of 'collections' supplied
   199  func (s *Store) GetPvtDataAndBlockByNum(blockNum uint64, filter ledger.PvtNsCollFilter) (*ledger.BlockAndPvtData, error) {
   200  	s.rwlock.RLock()
   201  	defer s.rwlock.RUnlock()
   202  
   203  	var block *common.Block
   204  	var pvtdata []*ledger.TxPvtData
   205  	var err error
   206  	if block, err = s.RetrieveBlockByNumber(blockNum); err != nil {
   207  		return nil, err
   208  	}
   209  	if pvtdata, err = s.getPvtDataByNumWithoutLock(blockNum, filter); err != nil {
   210  		return nil, err
   211  	}
   212  	return &ledger.BlockAndPvtData{Block: block, PvtData: constructPvtdataMap(pvtdata)}, nil
   213  }
   214  
   215  // GetPvtDataByNum returns only the pvt data  corresponding to the given block number
   216  // The pvt data is filtered by the list of 'ns/collections' supplied in the filter
   217  // A nil filter does not filter any results
   218  func (s *Store) GetPvtDataByNum(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
   219  	s.rwlock.RLock()
   220  	defer s.rwlock.RUnlock()
   221  	return s.getPvtDataByNumWithoutLock(blockNum, filter)
   222  }
   223  
   224  // getPvtDataByNumWithoutLock returns only the pvt data  corresponding to the given block number.
   225  // This function does not acquire a readlock and it is expected that in most of the circumstances, the caller
   226  // possesses a read lock on `s.rwlock`
   227  func (s *Store) getPvtDataByNumWithoutLock(blockNum uint64, filter ledger.PvtNsCollFilter) ([]*ledger.TxPvtData, error) {
   228  	var pvtdata []*ledger.TxPvtData
   229  	var err error
   230  	if pvtdata, err = s.pvtdataStore.GetPvtDataByBlockNum(blockNum, filter); err != nil {
   231  		return nil, err
   232  	}
   233  	return pvtdata, nil
   234  }
   235  
   236  // DoesPvtDataInfoExist returns true when
   237  // (1) the ledger has pvtdata associated with the given block number (or)
   238  // (2) a few or all pvtdata associated with the given block number is missing but the
   239  //     missing info is recorded in the ledger (or)
   240  // (3) the block is committed does not contain any pvtData.
   241  func (s *Store) DoesPvtDataInfoExist(blockNum uint64) (bool, error) {
   242  	pvtStoreHt, err := s.pvtdataStore.LastCommittedBlockHeight()
   243  	if err != nil {
   244  		return false, err
   245  	}
   246  	return blockNum+1 <= pvtStoreHt, nil
   247  }
   248  
   249  // GetMissingPvtDataInfoForMostRecentBlocks invokes the function on underlying pvtdata store
   250  func (s *Store) GetMissingPvtDataInfoForMostRecentBlocks(maxBlock int) (ledger.MissingPvtDataInfo, error) {
   251  	// it is safe to not acquire a read lock on s.rwlock. Without a lock, the value of
   252  	// lastCommittedBlock can change due to a new block commit. As a result, we may not
   253  	// be able to fetch the missing data info of truly the most recent blocks. This
   254  	// decision was made to ensure that the regular block commit rate is not affected.
   255  	return s.pvtdataStore.GetMissingPvtDataInfoForMostRecentBlocks(maxBlock)
   256  }
   257  
   258  // ProcessCollsEligibilityEnabled invokes the function on underlying pvtdata store
   259  func (s *Store) ProcessCollsEligibilityEnabled(committingBlk uint64, nsCollMap map[string][]string) error {
   260  	return s.pvtdataStore.ProcessCollsEligibilityEnabled(committingBlk, nsCollMap)
   261  }
   262  
   263  // GetLastUpdatedOldBlocksPvtData invokes the function on underlying pvtdata store
   264  func (s *Store) GetLastUpdatedOldBlocksPvtData() (map[uint64][]*ledger.TxPvtData, error) {
   265  	return s.pvtdataStore.GetLastUpdatedOldBlocksPvtData()
   266  }
   267  
   268  // ResetLastUpdatedOldBlocksList invokes the function on underlying pvtdata store
   269  func (s *Store) ResetLastUpdatedOldBlocksList() error {
   270  	return s.pvtdataStore.ResetLastUpdatedOldBlocksList()
   271  }
   272  
   273  // IsPvtStoreAheadOfBlockStore returns true when the pvtStore height is
   274  // greater than the blockstore height. Otherwise, it returns false.
   275  func (s *Store) IsPvtStoreAheadOfBlockStore() bool {
   276  	return s.isPvtstoreAheadOfBlockstore.Load().(bool)
   277  }
   278  
   279  // TODO: FAB-16297 -- Remove init() as it is no longer needed. The private data feature
   280  // became stable from v1.2 onwards. To allow the initiation of pvtdata store with non-zero
   281  // block height (mainly during a rolling upgrade from an existing v1.1 network to v1.2),
   282  // we introduced pvtdata init() function which would take the height of block store and
   283  // set it as a height of pvtdataStore. From v2.0 onwards, it is no longer needed as we do
   284  // not support a rolling upgrade from v1.1 to v2.0
   285  
   286  // init first invokes function `initFromExistingBlockchain`
   287  // in order to check whether the pvtdata store is present because of an upgrade
   288  // of peer from 1.0 and need to be updated with the existing blockchain. If, this is
   289  // not the case then this init will invoke function `syncPvtdataStoreWithBlockStore`
   290  // to follow the normal course
   291  func (s *Store) init() error {
   292  	var initialized bool
   293  	var err error
   294  	if initialized, err = s.initPvtdataStoreFromExistingBlockchain(); err != nil || initialized {
   295  		return err
   296  	}
   297  	return nil
   298  }
   299  
   300  // initPvtdataStoreFromExistingBlockchain updates the initial state of the pvtdata store
   301  // if an existing block store has a blockchain and the pvtdata store is empty.
   302  // This situation is expected to happen when a peer is upgrated from version 1.0
   303  // and an existing blockchain is present that was generated with version 1.0.
   304  // Under this scenario, the pvtdata store is brought upto the point as if it has
   305  // processed existing blocks with no pvt data. This function returns true if the
   306  // above mentioned condition is found to be true and pvtdata store is successfully updated
   307  func (s *Store) initPvtdataStoreFromExistingBlockchain() (bool, error) {
   308  	var bcInfo *common.BlockchainInfo
   309  	var pvtdataStoreEmpty bool
   310  	var err error
   311  
   312  	if bcInfo, err = s.BlockStore.GetBlockchainInfo(); err != nil {
   313  		return false, err
   314  	}
   315  	if pvtdataStoreEmpty, err = s.pvtdataStore.IsEmpty(); err != nil {
   316  		return false, err
   317  	}
   318  	if pvtdataStoreEmpty && bcInfo.Height > 0 {
   319  		if err = s.pvtdataStore.InitLastCommittedBlock(bcInfo.Height - 1); err != nil {
   320  			return false, err
   321  		}
   322  		return true, nil
   323  	}
   324  	return false, nil
   325  }
   326  
   327  func constructPvtdataMap(pvtdata []*ledger.TxPvtData) ledger.TxPvtDataMap {
   328  	if pvtdata == nil {
   329  		return nil
   330  	}
   331  	m := make(map[uint64]*ledger.TxPvtData)
   332  	for _, pvtdatum := range pvtdata {
   333  		m[pvtdatum.SeqInBlock] = pvtdatum
   334  	}
   335  	return m
   336  }
   337  
   338  // LoadPreResetHeight returns the pre reset height for the specified ledgers.
   339  func LoadPreResetHeight(blockstorePath string, ledgerIDs []string) (map[string]uint64, error) {
   340  	return fsblkstorage.LoadPreResetHeight(blockstorePath, ledgerIDs)
   341  }
   342  
   343  // ResetBlockStore resets all ledgers to the genesis block.
   344  func ResetBlockStore(blockstorePath string) error {
   345  	return fsblkstorage.ResetBlockStore(blockstorePath)
   346  }
   347  
   348  // ValidateRollbackParams performs necessary validation on the input given for
   349  // the rollback operation.
   350  func ValidateRollbackParams(blockstorePath, ledgerID string, blockNum uint64) error {
   351  	return fsblkstorage.ValidateRollbackParams(blockstorePath, ledgerID, blockNum)
   352  }
   353  
   354  // Rollback reverts changes made to the block store beyond a given block number.
   355  func Rollback(blockstorePath, ledgerID string, blockNum uint64) error {
   356  	indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
   357  	return fsblkstorage.Rollback(blockstorePath, ledgerID, blockNum, indexConfig)
   358  }