github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/kv_ledger_provider.go (about)

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