github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/kv_ledger_provider.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hechain20/hechain/common/ledger/blkstorage"
    17  	"github.com/hechain20/hechain/common/ledger/dataformat"
    18  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    19  	"github.com/hechain20/hechain/core/ledger"
    20  	"github.com/hechain20/hechain/core/ledger/confighistory"
    21  	"github.com/hechain20/hechain/core/ledger/kvledger/bookkeeping"
    22  	"github.com/hechain20/hechain/core/ledger/kvledger/history"
    23  	"github.com/hechain20/hechain/core/ledger/kvledger/msgs"
    24  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/privacyenabledstate"
    25  	"github.com/hechain20/hechain/core/ledger/pvtdatastorage"
    26  	"github.com/hechain20/hechain/internal/fileutil"
    27  	"github.com/hechain20/hechain/protoutil"
    28  	"github.com/hyperledger/fabric-protos-go/common"
    29  	"github.com/pkg/errors"
    30  	"github.com/syndtr/goleveldb/leveldb"
    31  )
    32  
    33  var (
    34  	// genesisBlkKeyPrefix is the prefix for each ledger key in idStore db
    35  	genesisBlkKeyPrefix = []byte{'l'}
    36  	// genesisBlkKeyStop is the end key when querying idStore db by ledger key
    37  	genesisBlkKeyStop = []byte{'l' + 1}
    38  	// metadataKeyPrefix is the prefix for each metadata key in idStore db
    39  	metadataKeyPrefix = []byte{'s'}
    40  	// metadataKeyStop is the end key when querying idStore db by metadata key
    41  	metadataKeyStop = []byte{'s' + 1}
    42  
    43  	// formatKey
    44  	formatKey = []byte("f")
    45  
    46  	attrsToIndex = []blkstorage.IndexableAttr{
    47  		blkstorage.IndexableAttrBlockHash,
    48  		blkstorage.IndexableAttrBlockNum,
    49  		blkstorage.IndexableAttrTxID,
    50  		blkstorage.IndexableAttrBlockNumTranNum,
    51  	}
    52  )
    53  
    54  const maxBlockFileSize = 64 * 1024 * 1024
    55  
    56  // Provider implements interface ledger.PeerLedgerProvider
    57  type Provider struct {
    58  	idStore              *idStore
    59  	blkStoreProvider     *blkstorage.BlockStoreProvider
    60  	pvtdataStoreProvider *pvtdatastorage.Provider
    61  	dbProvider           *privacyenabledstate.DBProvider
    62  	historydbProvider    *history.DBProvider
    63  	configHistoryMgr     *confighistory.Mgr
    64  	stateListeners       []ledger.StateListener
    65  	bookkeepingProvider  *bookkeeping.Provider
    66  	initializer          *ledger.Initializer
    67  	collElgNotifier      *collElgNotifier
    68  	stats                *stats
    69  	fileLock             *leveldbhelper.FileLock
    70  }
    71  
    72  // NewProvider instantiates a new Provider.
    73  // This is not thread-safe and assumed to be synchronized by the caller
    74  func NewProvider(initializer *ledger.Initializer) (pr *Provider, e error) {
    75  	p := &Provider{
    76  		initializer: initializer,
    77  	}
    78  
    79  	defer func() {
    80  		if e != nil {
    81  			p.Close()
    82  			if errFormatMismatch, ok := e.(*dataformat.ErrFormatMismatch); ok {
    83  				if errFormatMismatch.Format == dataformat.PreviousFormat && errFormatMismatch.ExpectedFormat == dataformat.CurrentFormat {
    84  					logger.Errorf("Please execute the 'peer node upgrade-dbs' command to upgrade the database format: %s", errFormatMismatch)
    85  				} else {
    86  					logger.Errorf("Please check the Fabric version matches the ledger data format: %s", errFormatMismatch)
    87  				}
    88  			}
    89  		}
    90  	}()
    91  
    92  	fileLockPath := fileLockPath(initializer.Config.RootFSPath)
    93  	fileLock := leveldbhelper.NewFileLock(fileLockPath)
    94  	if err := fileLock.Lock(); err != nil {
    95  		return nil, errors.Wrap(err, "as another peer node command is executing,"+
    96  			" wait for that command to complete its execution or terminate it before retrying")
    97  	}
    98  
    99  	p.fileLock = fileLock
   100  
   101  	if err := p.initLedgerIDInventory(); err != nil {
   102  		return nil, err
   103  	}
   104  	if err := p.initBlockStoreProvider(); err != nil {
   105  		return nil, err
   106  	}
   107  	if err := p.initPvtDataStoreProvider(); err != nil {
   108  		return nil, err
   109  	}
   110  	if err := p.initHistoryDBProvider(); err != nil {
   111  		return nil, err
   112  	}
   113  	if err := p.initConfigHistoryManager(); err != nil {
   114  		return nil, err
   115  	}
   116  	p.initCollElgNotifier()
   117  	p.initStateListeners()
   118  	if err := p.initStateDBProvider(); err != nil {
   119  		return nil, err
   120  	}
   121  	p.initLedgerStatistics()
   122  	if err := p.deletePartialLedgers(); err != nil {
   123  		return nil, err
   124  	}
   125  	if err := p.initSnapshotDir(); err != nil {
   126  		return nil, err
   127  	}
   128  	return p, nil
   129  }
   130  
   131  func (p *Provider) initLedgerIDInventory() error {
   132  	idStore, err := openIDStore(LedgerProviderPath(p.initializer.Config.RootFSPath))
   133  	if err != nil {
   134  		return err
   135  	}
   136  	p.idStore = idStore
   137  	return nil
   138  }
   139  
   140  func (p *Provider) initBlockStoreProvider() error {
   141  	indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
   142  	blkStoreProvider, err := blkstorage.NewProvider(
   143  		blkstorage.NewConf(
   144  			BlockStorePath(p.initializer.Config.RootFSPath),
   145  			maxBlockFileSize,
   146  		),
   147  		indexConfig,
   148  		p.initializer.MetricsProvider,
   149  	)
   150  	if err != nil {
   151  		return err
   152  	}
   153  	p.blkStoreProvider = blkStoreProvider
   154  	return nil
   155  }
   156  
   157  func (p *Provider) initPvtDataStoreProvider() error {
   158  	privateDataConfig := &pvtdatastorage.PrivateDataConfig{
   159  		PrivateDataConfig: p.initializer.Config.PrivateDataConfig,
   160  		StorePath:         PvtDataStorePath(p.initializer.Config.RootFSPath),
   161  	}
   162  	pvtdataStoreProvider, err := pvtdatastorage.NewProvider(privateDataConfig)
   163  	if err != nil {
   164  		return err
   165  	}
   166  	p.pvtdataStoreProvider = pvtdataStoreProvider
   167  	return nil
   168  }
   169  
   170  func (p *Provider) initHistoryDBProvider() error {
   171  	if !p.initializer.Config.HistoryDBConfig.Enabled {
   172  		return nil
   173  	}
   174  	// Initialize the history database (index for history of values by key)
   175  	historydbProvider, err := history.NewDBProvider(
   176  		HistoryDBPath(p.initializer.Config.RootFSPath),
   177  	)
   178  	if err != nil {
   179  		return err
   180  	}
   181  	p.historydbProvider = historydbProvider
   182  	return nil
   183  }
   184  
   185  func (p *Provider) initConfigHistoryManager() error {
   186  	var err error
   187  	configHistoryMgr, err := confighistory.NewMgr(
   188  		ConfigHistoryDBPath(p.initializer.Config.RootFSPath),
   189  		p.initializer.DeployedChaincodeInfoProvider,
   190  	)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	p.configHistoryMgr = configHistoryMgr
   195  	return nil
   196  }
   197  
   198  func (p *Provider) initCollElgNotifier() {
   199  	collElgNotifier := &collElgNotifier{
   200  		p.initializer.DeployedChaincodeInfoProvider,
   201  		p.initializer.MembershipInfoProvider,
   202  		make(map[string]collElgListener),
   203  	}
   204  	p.collElgNotifier = collElgNotifier
   205  }
   206  
   207  func (p *Provider) initStateListeners() {
   208  	stateListeners := p.initializer.StateListeners
   209  	stateListeners = append(stateListeners, p.collElgNotifier)
   210  	stateListeners = append(stateListeners, p.configHistoryMgr)
   211  	p.stateListeners = stateListeners
   212  }
   213  
   214  func (p *Provider) initStateDBProvider() error {
   215  	var err error
   216  	p.bookkeepingProvider, err = bookkeeping.NewProvider(
   217  		BookkeeperDBPath(p.initializer.Config.RootFSPath),
   218  	)
   219  	if err != nil {
   220  		return err
   221  	}
   222  	stateDBConfig := &privacyenabledstate.StateDBConfig{
   223  		StateDBConfig: p.initializer.Config.StateDBConfig,
   224  		LevelDBPath:   StateDBPath(p.initializer.Config.RootFSPath),
   225  	}
   226  	sysNamespaces := p.initializer.DeployedChaincodeInfoProvider.Namespaces()
   227  	p.dbProvider, err = privacyenabledstate.NewDBProvider(
   228  		p.bookkeepingProvider,
   229  		p.initializer.MetricsProvider,
   230  		p.initializer.HealthCheckRegistry,
   231  		stateDBConfig,
   232  		sysNamespaces,
   233  	)
   234  	return err
   235  }
   236  
   237  func (p *Provider) initLedgerStatistics() {
   238  	p.stats = newStats(p.initializer.MetricsProvider)
   239  }
   240  
   241  func (p *Provider) initSnapshotDir() error {
   242  	snapshotsRootDir := p.initializer.Config.SnapshotsConfig.RootDir
   243  	if !filepath.IsAbs(snapshotsRootDir) {
   244  		return errors.Errorf("invalid path: %s. The path for the snapshot dir is expected to be an absolute path", snapshotsRootDir)
   245  	}
   246  
   247  	inProgressSnapshotsPath := SnapshotsTempDirPath(snapshotsRootDir)
   248  	completedSnapshotsPath := CompletedSnapshotsPath(snapshotsRootDir)
   249  
   250  	if err := os.RemoveAll(inProgressSnapshotsPath); err != nil {
   251  		return errors.Wrapf(err, "error while deleting the dir: %s", inProgressSnapshotsPath)
   252  	}
   253  	if err := os.MkdirAll(inProgressSnapshotsPath, 0o755); err != nil {
   254  		return errors.Wrapf(err, "error while creating the dir: %s, ensure peer has write access to configured ledger.snapshots.rootDir directory", inProgressSnapshotsPath)
   255  	}
   256  	if err := os.MkdirAll(completedSnapshotsPath, 0o755); err != nil {
   257  		return errors.Wrapf(err, "error while creating the dir: %s, ensure peer has write access to configured ledger.snapshots.rootDir directory", completedSnapshotsPath)
   258  	}
   259  	return fileutil.SyncDir(snapshotsRootDir)
   260  }
   261  
   262  // CreateFromGenesisBlock implements the corresponding method from interface ledger.PeerLedgerProvider
   263  // This function creates a new ledger and commits the genesis block. If a failure happens during this
   264  // process, the partially created ledger is deleted
   265  func (p *Provider) CreateFromGenesisBlock(genesisBlock *common.Block) (ledger.PeerLedger, error) {
   266  	ledgerID, err := protoutil.GetChannelIDFromBlock(genesisBlock)
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  	if err = p.idStore.createLedgerID(
   271  		ledgerID,
   272  		&msgs.LedgerMetadata{
   273  			Status: msgs.Status_UNDER_CONSTRUCTION,
   274  		},
   275  	); err != nil {
   276  		return nil, err
   277  	}
   278  
   279  	lgr, err := p.open(ledgerID, nil, false)
   280  	if err != nil {
   281  		return nil, p.deleteUnderConstructionLedger(lgr, ledgerID, err)
   282  	}
   283  
   284  	if err = lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: genesisBlock}, &ledger.CommitOptions{}); err != nil {
   285  		return nil, p.deleteUnderConstructionLedger(lgr, ledgerID, err)
   286  	}
   287  
   288  	if err = p.idStore.updateLedgerStatus(ledgerID, msgs.Status_ACTIVE); err != nil {
   289  		return nil, p.deleteUnderConstructionLedger(lgr, ledgerID, err)
   290  	}
   291  	return lgr, nil
   292  }
   293  
   294  func (p *Provider) deleteUnderConstructionLedger(ledger ledger.PeerLedger, ledgerID string, creationErr error) error {
   295  	if creationErr == nil {
   296  		return nil
   297  	} else {
   298  		logger.Errorf("ledger creation error = %+v", creationErr)
   299  	}
   300  
   301  	if ledger != nil {
   302  		ledger.Close()
   303  	}
   304  	cleanupErr := p.runCleanup(ledgerID)
   305  	if cleanupErr == nil {
   306  		return creationErr
   307  	}
   308  	return errors.WithMessagef(cleanupErr, creationErr.Error())
   309  }
   310  
   311  // Open implements the corresponding method from interface ledger.PeerLedgerProvider
   312  func (p *Provider) Open(ledgerID string) (ledger.PeerLedger, error) {
   313  	logger.Debugf("Open() opening kvledger: %s", ledgerID)
   314  	// Check the ID store to ensure that the chainId/ledgerId exists
   315  	ledgerMetadata, err := p.idStore.getLedgerMetadata(ledgerID)
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  	if ledgerMetadata == nil {
   320  		return nil, errors.Errorf("cannot open ledger [%s], ledger does not exist", ledgerID)
   321  	}
   322  	if ledgerMetadata.Status != msgs.Status_ACTIVE {
   323  		return nil, errors.Errorf("cannot open ledger [%s], ledger status is [%s]", ledgerID, ledgerMetadata.Status)
   324  	}
   325  
   326  	bootSnapshotMetadata, err := snapshotMetadataFromProto(ledgerMetadata.BootSnapshotMetadata)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  	return p.open(ledgerID, bootSnapshotMetadata, false)
   331  }
   332  
   333  func (p *Provider) open(ledgerID string, bootSnapshotMetadata *SnapshotMetadata, initializingFromSnapshot bool) (ledger.PeerLedger, error) {
   334  	// Get the block store for a chain/ledger
   335  	blockStore, err := p.blkStoreProvider.Open(ledgerID)
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	pvtdataStore, err := p.pvtdataStoreProvider.OpenStore(ledgerID)
   340  	if err != nil {
   341  		return nil, err
   342  	}
   343  
   344  	p.collElgNotifier.registerListener(ledgerID, pvtdataStore)
   345  
   346  	// Get the versioned database (state database) for a chain/ledger
   347  	channelInfoProvider := &channelInfoProvider{ledgerID, blockStore, p.collElgNotifier.deployedChaincodeInfoProvider}
   348  	db, err := p.dbProvider.GetDBHandle(ledgerID, channelInfoProvider)
   349  	if err != nil {
   350  		return nil, err
   351  	}
   352  
   353  	// Get the history database (index for history of values by key) for a chain/ledger
   354  	var historyDB *history.DB
   355  	if p.historydbProvider != nil {
   356  		historyDB = p.historydbProvider.GetDBHandle(ledgerID)
   357  	}
   358  
   359  	initializer := &lgrInitializer{
   360  		ledgerID:                 ledgerID,
   361  		blockStore:               blockStore,
   362  		pvtdataStore:             pvtdataStore,
   363  		stateDB:                  db,
   364  		historyDB:                historyDB,
   365  		configHistoryMgr:         p.configHistoryMgr,
   366  		stateListeners:           p.stateListeners,
   367  		bookkeeperProvider:       p.bookkeepingProvider,
   368  		ccInfoProvider:           p.initializer.DeployedChaincodeInfoProvider,
   369  		ccLifecycleEventProvider: p.initializer.ChaincodeLifecycleEventProvider,
   370  		stats:                    p.stats.ledgerStats(ledgerID),
   371  		customTxProcessors:       p.initializer.CustomTxProcessors,
   372  		hashProvider:             p.initializer.HashProvider,
   373  		config:                   p.initializer.Config,
   374  		bootSnapshotMetadata:     bootSnapshotMetadata,
   375  		initializingFromSnapshot: initializingFromSnapshot,
   376  	}
   377  
   378  	l, err := newKVLedger(initializer)
   379  	if err != nil {
   380  		return nil, err
   381  	}
   382  	return l, nil
   383  }
   384  
   385  // Exists implements the corresponding method from interface ledger.PeerLedgerProvider
   386  func (p *Provider) Exists(ledgerID string) (bool, error) {
   387  	return p.idStore.ledgerIDExists(ledgerID)
   388  }
   389  
   390  // List implements the corresponding method from interface ledger.PeerLedgerProvider
   391  func (p *Provider) List() ([]string, error) {
   392  	return p.idStore.getActiveLedgerIDs()
   393  }
   394  
   395  // Close implements the corresponding method from interface ledger.PeerLedgerProvider
   396  func (p *Provider) Close() {
   397  	if p.idStore != nil {
   398  		p.idStore.close()
   399  	}
   400  	if p.blkStoreProvider != nil {
   401  		p.blkStoreProvider.Close()
   402  	}
   403  	if p.pvtdataStoreProvider != nil {
   404  		p.pvtdataStoreProvider.Close()
   405  	}
   406  	if p.dbProvider != nil {
   407  		p.dbProvider.Close()
   408  	}
   409  	if p.bookkeepingProvider != nil {
   410  		p.bookkeepingProvider.Close()
   411  	}
   412  	if p.configHistoryMgr != nil {
   413  		p.configHistoryMgr.Close()
   414  	}
   415  	if p.historydbProvider != nil {
   416  		p.historydbProvider.Close()
   417  	}
   418  	if p.fileLock != nil {
   419  		p.fileLock.Unlock()
   420  	}
   421  }
   422  
   423  // deletePartialLedgers scans for and deletes any ledger with a status of UNDER_CONSTRUCTION or UNDER_DELETION.
   424  // UNDER_CONSTRUCTION ledgers represent residual structures created as a side effect of a crash during ledger creation.
   425  // UNDER_DELETION ledgers represent residual structures created as a side effect of a crash during a peer channel unjoin.
   426  func (p *Provider) deletePartialLedgers() error {
   427  	logger.Debug("Removing ledgers in state UNDER_CONSTRUCTION or UNDER_DELETION")
   428  	itr := p.idStore.db.GetIterator(metadataKeyPrefix, metadataKeyStop)
   429  	defer itr.Release()
   430  	if err := itr.Error(); err != nil {
   431  		return errors.WithMessage(err, "error obtaining iterator for incomplete ledger scans")
   432  	}
   433  	for {
   434  		hasMore := itr.Next()
   435  		err := itr.Error()
   436  		if err != nil {
   437  			return errors.WithMessage(err, "error while iterating over ledger list while scanning for incomplete ledgers")
   438  		}
   439  		if !hasMore {
   440  			return nil
   441  		}
   442  		ledgerID := ledgerIDFromMetadataKey(itr.Key())
   443  		metadata := &msgs.LedgerMetadata{}
   444  		if err := proto.Unmarshal(itr.Value(), metadata); err != nil {
   445  			return errors.Wrapf(err, "error while unmarshalling metadata bytes for ledger [%s]", ledgerID)
   446  		}
   447  		if metadata.Status == msgs.Status_UNDER_CONSTRUCTION || metadata.Status == msgs.Status_UNDER_DELETION {
   448  			logger.Infow(
   449  				"A partial ledger was identified at peer launch, indicating a peer stop/crash during creation or a failed channel unjoin.  The partial ledger wil be deleted.",
   450  				"ledgerID", ledgerID,
   451  				"Status", metadata.Status,
   452  			)
   453  			if err := p.runCleanup(ledgerID); err != nil {
   454  				logger.Errorw(
   455  					"Error while deleting a partially created ledger at start",
   456  					"ledgerID", ledgerID,
   457  					"Status", metadata.Status,
   458  					"error", err,
   459  				)
   460  				return errors.WithMessagef(err, "error while deleting a partially constructed ledger with status [%s] at start for ledger = [%s]", metadata.Status, ledgerID)
   461  			}
   462  		}
   463  	}
   464  }
   465  
   466  // runCleanup cleans up blockstorage, statedb, and historydb for what
   467  // may have got created during in-complete ledger creation
   468  func (p *Provider) runCleanup(ledgerID string) error {
   469  	ledgerDataRemover := &ledgerDataRemover{
   470  		blkStoreProvider:     p.blkStoreProvider,
   471  		statedbProvider:      p.dbProvider,
   472  		bookkeepingProvider:  p.bookkeepingProvider,
   473  		configHistoryMgr:     p.configHistoryMgr,
   474  		historydbProvider:    p.historydbProvider,
   475  		pvtdataStoreProvider: p.pvtdataStoreProvider,
   476  	}
   477  	if err := ledgerDataRemover.Drop(ledgerID); err != nil {
   478  		return errors.WithMessagef(err, "error while deleting data from ledger [%s]", ledgerID)
   479  	}
   480  
   481  	return p.idStore.deleteLedgerID(ledgerID)
   482  }
   483  
   484  func snapshotMetadataFromProto(p *msgs.BootSnapshotMetadata) (*SnapshotMetadata, error) {
   485  	if p == nil {
   486  		return nil, nil
   487  	}
   488  
   489  	m := &SnapshotMetadataJSONs{
   490  		signableMetadata:   p.SingableMetadata,
   491  		additionalMetadata: p.AdditionalMetadata,
   492  	}
   493  
   494  	return m.ToMetadata()
   495  }
   496  
   497  //////////////////////////////////////////////////////////////////////
   498  // Ledger id persistence related code
   499  ///////////////////////////////////////////////////////////////////////
   500  type idStore struct {
   501  	db     *leveldbhelper.DB
   502  	dbPath string
   503  }
   504  
   505  func openIDStore(path string) (s *idStore, e error) {
   506  	db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: path})
   507  	db.Open()
   508  	defer func() {
   509  		if e != nil {
   510  			db.Close()
   511  		}
   512  	}()
   513  
   514  	emptyDB, err := db.IsEmpty()
   515  	if err != nil {
   516  		return nil, err
   517  	}
   518  
   519  	expectedFormatBytes := []byte(dataformat.CurrentFormat)
   520  	if emptyDB {
   521  		// add format key to a new db
   522  		err := db.Put(formatKey, expectedFormatBytes, true)
   523  		if err != nil {
   524  			return nil, err
   525  		}
   526  		return &idStore{db, path}, nil
   527  	}
   528  
   529  	// verify the format is current for an existing db
   530  	format, err := db.Get(formatKey)
   531  	if err != nil {
   532  		return nil, err
   533  	}
   534  	if !bytes.Equal(format, expectedFormatBytes) {
   535  		logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).",
   536  			path, dataformat.CurrentFormat, expectedFormatBytes, format, format)
   537  		return nil, &dataformat.ErrFormatMismatch{
   538  			ExpectedFormat: dataformat.CurrentFormat,
   539  			Format:         string(format),
   540  			DBInfo:         fmt.Sprintf("leveldb for channel-IDs at [%s]", path),
   541  		}
   542  	}
   543  	return &idStore{db, path}, nil
   544  }
   545  
   546  // checkUpgradeEligibility checks if the format is eligible to upgrade.
   547  // It returns true if the format is eligible to upgrade to the current format.
   548  // It returns false if either the format is the current format or the db is empty.
   549  // Otherwise, an ErrFormatMismatch is returned.
   550  func (s *idStore) checkUpgradeEligibility() (bool, error) {
   551  	emptydb, err := s.db.IsEmpty()
   552  	if err != nil {
   553  		return false, err
   554  	}
   555  	if emptydb {
   556  		logger.Warnf("Ledger database %s is empty, nothing to upgrade", s.dbPath)
   557  		return false, nil
   558  	}
   559  	format, err := s.db.Get(formatKey)
   560  	if err != nil {
   561  		return false, err
   562  	}
   563  	if bytes.Equal(format, []byte(dataformat.CurrentFormat)) {
   564  		logger.Debugf("Ledger database %s has current data format, nothing to upgrade", s.dbPath)
   565  		return false, nil
   566  	}
   567  	if !bytes.Equal(format, []byte(dataformat.PreviousFormat)) {
   568  		err = &dataformat.ErrFormatMismatch{
   569  			ExpectedFormat: dataformat.PreviousFormat,
   570  			Format:         string(format),
   571  			DBInfo:         fmt.Sprintf("leveldb for channel-IDs at [%s]", s.dbPath),
   572  		}
   573  		return false, err
   574  	}
   575  	return true, nil
   576  }
   577  
   578  func (s *idStore) upgradeFormat() error {
   579  	eligible, err := s.checkUpgradeEligibility()
   580  	if err != nil {
   581  		return err
   582  	}
   583  	if !eligible {
   584  		return nil
   585  	}
   586  
   587  	logger.Infof("Upgrading ledgerProvider database to the new format %s", dataformat.CurrentFormat)
   588  
   589  	batch := &leveldb.Batch{}
   590  	batch.Put(formatKey, []byte(dataformat.CurrentFormat))
   591  
   592  	// add new metadata key for each ledger (channel)
   593  	metadata, err := protoutil.Marshal(&msgs.LedgerMetadata{Status: msgs.Status_ACTIVE})
   594  	if err != nil {
   595  		logger.Errorf("Error marshalling ledger metadata: %s", err)
   596  		return errors.Wrapf(err, "error marshalling ledger metadata")
   597  	}
   598  	itr := s.db.GetIterator(genesisBlkKeyPrefix, genesisBlkKeyStop)
   599  	defer itr.Release()
   600  	for itr.Error() == nil && itr.Next() {
   601  		id := ledgerIDFromGenesisBlockKey(itr.Key())
   602  		batch.Put(metadataKey(id), metadata)
   603  	}
   604  	if err = itr.Error(); err != nil {
   605  		logger.Errorf("Error while upgrading idStore format: %s", err)
   606  		return errors.Wrapf(err, "error while upgrading idStore format")
   607  	}
   608  
   609  	return s.db.WriteBatch(batch, true)
   610  }
   611  
   612  func (s *idStore) createLedgerID(ledgerID string, metadata *msgs.LedgerMetadata) error {
   613  	m, err := s.getLedgerMetadata(ledgerID)
   614  	if err != nil {
   615  		return err
   616  	}
   617  	if m != nil {
   618  		return errors.Errorf("ledger [%s] already exists with state [%s]", ledgerID, m.GetStatus())
   619  	}
   620  	metadataBytes, err := protoutil.Marshal(metadata)
   621  	if err != nil {
   622  		return err
   623  	}
   624  	return s.db.Put(metadataKey(ledgerID), metadataBytes, true)
   625  }
   626  
   627  func (s *idStore) deleteLedgerID(ledgerID string) error {
   628  	return s.db.Delete(metadataKey(ledgerID), true)
   629  }
   630  
   631  func (s *idStore) updateLedgerStatus(ledgerID string, newStatus msgs.Status) error {
   632  	metadata, err := s.getLedgerMetadata(ledgerID)
   633  	if err != nil {
   634  		return err
   635  	}
   636  	if metadata == nil {
   637  		logger.Errorf("LedgerID [%s] does not exist", ledgerID)
   638  		return errors.Errorf("cannot update ledger status, ledger [%s] does not exist", ledgerID)
   639  	}
   640  	if metadata.Status == newStatus {
   641  		logger.Infof("Ledger [%s] is already in [%s] status, nothing to do", ledgerID, newStatus)
   642  		return nil
   643  	}
   644  	metadata.Status = newStatus
   645  	metadataBytes, err := proto.Marshal(metadata)
   646  	if err != nil {
   647  		logger.Errorf("Error marshalling ledger metadata: %s", err)
   648  		return errors.Wrapf(err, "error marshalling ledger metadata")
   649  	}
   650  	logger.Infof("Updating ledger [%s] status to [%s]", ledgerID, newStatus)
   651  	key := metadataKey(ledgerID)
   652  	return s.db.Put(key, metadataBytes, true)
   653  }
   654  
   655  func (s *idStore) getLedgerMetadata(ledgerID string) (*msgs.LedgerMetadata, error) {
   656  	val, err := s.db.Get(metadataKey(ledgerID))
   657  	if val == nil || err != nil {
   658  		return nil, err
   659  	}
   660  	metadata := &msgs.LedgerMetadata{}
   661  	if err := proto.Unmarshal(val, metadata); err != nil {
   662  		logger.Errorf("Error unmarshalling ledger metadata: %s", err)
   663  		return nil, errors.Wrapf(err, "error unmarshalling ledger metadata")
   664  	}
   665  	return metadata, nil
   666  }
   667  
   668  func (s *idStore) ledgerIDExists(ledgerID string) (bool, error) {
   669  	key := metadataKey(ledgerID)
   670  	val, err := s.db.Get(key)
   671  	if err != nil {
   672  		return false, err
   673  	}
   674  	return val != nil, nil
   675  }
   676  
   677  func (s *idStore) getActiveLedgerIDs() ([]string, error) {
   678  	var ids []string
   679  	itr := s.db.GetIterator(metadataKeyPrefix, metadataKeyStop)
   680  	defer itr.Release()
   681  	for itr.Error() == nil && itr.Next() {
   682  		metadata := &msgs.LedgerMetadata{}
   683  		if err := proto.Unmarshal(itr.Value(), metadata); err != nil {
   684  			logger.Errorf("Error unmarshalling ledger metadata: %s", err)
   685  			return nil, errors.Wrapf(err, "error unmarshalling ledger metadata")
   686  		}
   687  		if metadata.Status == msgs.Status_ACTIVE {
   688  			id := ledgerIDFromMetadataKey(itr.Key())
   689  			ids = append(ids, id)
   690  		}
   691  	}
   692  	if err := itr.Error(); err != nil {
   693  		logger.Errorf("Error getting ledger ids from idStore: %s", err)
   694  		return nil, errors.Wrapf(err, "error getting ledger ids from idStore")
   695  	}
   696  	return ids, nil
   697  }
   698  
   699  func (s *idStore) close() {
   700  	s.db.Close()
   701  }
   702  
   703  func ledgerIDFromGenesisBlockKey(key []byte) string {
   704  	return string(key[len(genesisBlkKeyPrefix):])
   705  }
   706  
   707  func metadataKey(ledgerID string) []byte {
   708  	return append(metadataKeyPrefix, []byte(ledgerID)...)
   709  }
   710  
   711  func ledgerIDFromMetadataKey(key []byte) string {
   712  	return string(key[len(metadataKeyPrefix):])
   713  }