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

     1  /*
     2  Copyright hechain. 2022 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package kvledger
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"strconv"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/golang/protobuf/proto"
    19  	"github.com/hechain20/hechain/bccsp/sw"
    20  	configtxtest "github.com/hechain20/hechain/common/configtx/test"
    21  	"github.com/hechain20/hechain/common/ledger/blkstorage"
    22  	"github.com/hechain20/hechain/common/ledger/dataformat"
    23  	"github.com/hechain20/hechain/common/ledger/testutil"
    24  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    25  	"github.com/hechain20/hechain/common/metrics/disabled"
    26  	"github.com/hechain20/hechain/common/util"
    27  	"github.com/hechain20/hechain/core/ledger"
    28  	"github.com/hechain20/hechain/core/ledger/kvledger/msgs"
    29  	"github.com/hechain20/hechain/core/ledger/mock"
    30  	"github.com/hechain20/hechain/protoutil"
    31  	"github.com/hyperledger/fabric-protos-go/common"
    32  	"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
    33  	"github.com/hyperledger/fabric-protos-go/peer"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  func TestLedgerProvider(t *testing.T) {
    38  	testcases := []struct {
    39  		enableHistoryDB bool
    40  	}{
    41  		{
    42  			enableHistoryDB: true,
    43  		},
    44  		{
    45  			enableHistoryDB: false,
    46  		},
    47  	}
    48  
    49  	for i, tc := range testcases {
    50  		t.Run(strconv.Itoa(i), func(t *testing.T) {
    51  			testLedgerProvider(t, tc.enableHistoryDB)
    52  		})
    53  	}
    54  }
    55  
    56  func testLedgerProvider(t *testing.T, enableHistoryDB bool) {
    57  	conf, cleanup := testConfig(t)
    58  	conf.HistoryDBConfig.Enabled = enableHistoryDB
    59  	defer cleanup()
    60  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
    61  	numLedgers := 10
    62  	existingLedgerIDs, err := provider.List()
    63  	require.NoError(t, err)
    64  	require.Len(t, existingLedgerIDs, 0)
    65  	genesisBlocks := make([]*common.Block, numLedgers)
    66  	for i := 0; i < numLedgers; i++ {
    67  		genesisBlock, _ := configtxtest.MakeGenesisBlock(constructTestLedgerID(i))
    68  		genesisBlocks[i] = genesisBlock
    69  		_, err := provider.CreateFromGenesisBlock(genesisBlock)
    70  		require.NoError(t, err)
    71  	}
    72  	existingLedgerIDs, err = provider.List()
    73  	require.NoError(t, err)
    74  	require.Len(t, existingLedgerIDs, numLedgers)
    75  
    76  	// verify formatKey is present in idStore
    77  	s := provider.idStore
    78  	val, err := s.db.Get(formatKey)
    79  	require.NoError(t, err)
    80  	require.Equal(t, []byte(dataformat.CurrentFormat), val)
    81  
    82  	provider.Close()
    83  
    84  	provider = testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
    85  	defer provider.Close()
    86  	ledgerIds, _ := provider.List()
    87  	require.Len(t, ledgerIds, numLedgers)
    88  	for i := 0; i < numLedgers; i++ {
    89  		require.Equal(t, constructTestLedgerID(i), ledgerIds[i])
    90  	}
    91  	for i := 0; i < numLedgers; i++ {
    92  		ledgerid := constructTestLedgerID(i)
    93  		status, _ := provider.Exists(ledgerid)
    94  		require.True(t, status)
    95  		ledger, err := provider.Open(ledgerid)
    96  		require.NoError(t, err)
    97  		bcInfo, err := ledger.GetBlockchainInfo()
    98  		ledger.Close()
    99  		require.NoError(t, err)
   100  		require.Equal(t, uint64(1), bcInfo.Height)
   101  
   102  		// check that ledger metadata keys were persisted in idStore with active status
   103  		s := provider.idStore
   104  		val, err := s.db.Get(metadataKey(ledgerid))
   105  		require.NoError(t, err)
   106  		metadata := &msgs.LedgerMetadata{}
   107  		require.NoError(t, proto.Unmarshal(val, metadata))
   108  		require.Equal(t, msgs.Status_ACTIVE, metadata.Status)
   109  	}
   110  	gb, _ := configtxtest.MakeGenesisBlock(constructTestLedgerID(2))
   111  	_, err = provider.CreateFromGenesisBlock(gb)
   112  	require.EqualError(t, err, "ledger [ledger_000002] already exists with state [ACTIVE]")
   113  
   114  	status, err := provider.Exists(constructTestLedgerID(numLedgers))
   115  	require.NoError(t, err, "Failed to check for ledger existence")
   116  	require.Equal(t, status, false)
   117  
   118  	_, err = provider.Open(constructTestLedgerID(numLedgers))
   119  	require.EqualError(t, err, "cannot open ledger [ledger_000010], ledger does not exist")
   120  }
   121  
   122  func TestGetActiveLedgerIDsIteratorError(t *testing.T) {
   123  	conf, cleanup := testConfig(t)
   124  	defer cleanup()
   125  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   126  
   127  	for i := 0; i < 2; i++ {
   128  		genesisBlock, _ := configtxtest.MakeGenesisBlock(constructTestLedgerID(i))
   129  		_, err := provider.CreateFromGenesisBlock(genesisBlock)
   130  		require.NoError(t, err)
   131  	}
   132  
   133  	// close provider to trigger db error
   134  	provider.Close()
   135  	_, err := provider.idStore.getActiveLedgerIDs()
   136  	require.EqualError(t, err, "error getting ledger ids from idStore: leveldb: closed")
   137  }
   138  
   139  func TestLedgerMetataDataUnmarshalError(t *testing.T) {
   140  	conf, cleanup := testConfig(t)
   141  	defer cleanup()
   142  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   143  	defer provider.Close()
   144  
   145  	ledgerID := constructTestLedgerID(0)
   146  	genesisBlock, _ := configtxtest.MakeGenesisBlock(ledgerID)
   147  	_, err := provider.CreateFromGenesisBlock(genesisBlock)
   148  	require.NoError(t, err)
   149  
   150  	// put invalid bytes for the metatdata key
   151  	require.NoError(t, provider.idStore.db.Put(metadataKey(ledgerID), []byte("invalid"), true))
   152  
   153  	_, err = provider.List()
   154  	require.EqualError(t, err, "error unmarshalling ledger metadata: unexpected EOF")
   155  
   156  	_, err = provider.Open(ledgerID)
   157  	require.EqualError(t, err, "error unmarshalling ledger metadata: unexpected EOF")
   158  }
   159  
   160  func TestNewProviderIdStoreFormatError(t *testing.T) {
   161  	conf, cleanup := testConfig(t)
   162  	defer cleanup()
   163  
   164  	require.NoError(t, testutil.Unzip("tests/testdata/v11/sample_ledgers/ledgersData.zip", conf.RootFSPath, false))
   165  
   166  	// NewProvider fails because ledgerProvider (idStore) has old format
   167  	_, err := NewProvider(
   168  		&ledger.Initializer{
   169  			DeployedChaincodeInfoProvider: &mock.DeployedChaincodeInfoProvider{},
   170  			MetricsProvider:               &disabled.Provider{},
   171  			Config:                        conf,
   172  		},
   173  	)
   174  	require.EqualError(t, err, fmt.Sprintf("unexpected format. db info = [leveldb for channel-IDs at [%s]], data format = [], expected format = [2.0]", LedgerProviderPath(conf.RootFSPath)))
   175  }
   176  
   177  func TestUpgradeIDStoreFormatDBError(t *testing.T) {
   178  	conf, cleanup := testConfig(t)
   179  	defer cleanup()
   180  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   181  	provider.Close()
   182  
   183  	err := provider.idStore.upgradeFormat()
   184  	dbPath := LedgerProviderPath(conf.RootFSPath)
   185  	require.EqualError(t, err, fmt.Sprintf("error while trying to see if the leveldb at path [%s] is empty: leveldb: closed", dbPath))
   186  }
   187  
   188  func TestCheckUpgradeEligibilityV1x(t *testing.T) {
   189  	conf, cleanup := testConfig(t)
   190  	defer cleanup()
   191  	dbPath := LedgerProviderPath(conf.RootFSPath)
   192  	db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: dbPath})
   193  	idStore := &idStore{db, dbPath}
   194  	db.Open()
   195  	defer db.Close()
   196  
   197  	// write a tmpKey so that idStore is not be empty
   198  	err := idStore.db.Put([]byte("tmpKey"), []byte("tmpValue"), true)
   199  	require.NoError(t, err)
   200  
   201  	eligible, err := idStore.checkUpgradeEligibility()
   202  	require.NoError(t, err)
   203  	require.True(t, eligible)
   204  }
   205  
   206  func TestCheckUpgradeEligibilityCurrentVersion(t *testing.T) {
   207  	conf, cleanup := testConfig(t)
   208  	defer cleanup()
   209  	dbPath := LedgerProviderPath(conf.RootFSPath)
   210  	db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: dbPath})
   211  	idStore := &idStore{db, dbPath}
   212  	db.Open()
   213  	defer db.Close()
   214  
   215  	err := idStore.db.Put(formatKey, []byte(dataformat.CurrentFormat), true)
   216  	require.NoError(t, err)
   217  
   218  	eligible, err := idStore.checkUpgradeEligibility()
   219  	require.NoError(t, err)
   220  	require.False(t, eligible)
   221  }
   222  
   223  func TestCheckUpgradeEligibilityBadFormat(t *testing.T) {
   224  	conf, cleanup := testConfig(t)
   225  	defer cleanup()
   226  	dbPath := LedgerProviderPath(conf.RootFSPath)
   227  	db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: dbPath})
   228  	idStore := &idStore{db, dbPath}
   229  	db.Open()
   230  	defer db.Close()
   231  
   232  	err := idStore.db.Put(formatKey, []byte("x.0"), true)
   233  	require.NoError(t, err)
   234  
   235  	expectedErr := &dataformat.ErrFormatMismatch{
   236  		ExpectedFormat: dataformat.PreviousFormat,
   237  		Format:         "x.0",
   238  		DBInfo:         fmt.Sprintf("leveldb for channel-IDs at [%s]", LedgerProviderPath(conf.RootFSPath)),
   239  	}
   240  	eligible, err := idStore.checkUpgradeEligibility()
   241  	require.EqualError(t, err, expectedErr.Error())
   242  	require.False(t, eligible)
   243  }
   244  
   245  func TestCheckUpgradeEligibilityEmptyDB(t *testing.T) {
   246  	conf, cleanup := testConfig(t)
   247  	defer cleanup()
   248  	dbPath := LedgerProviderPath(conf.RootFSPath)
   249  	db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: dbPath})
   250  	idStore := &idStore{db, dbPath}
   251  	db.Open()
   252  	defer db.Close()
   253  
   254  	eligible, err := idStore.checkUpgradeEligibility()
   255  	require.NoError(t, err)
   256  	require.False(t, eligible)
   257  }
   258  
   259  func TestDeletionOfUnderConstructionLedgersAtStart(t *testing.T) {
   260  	testcases := []struct {
   261  		enableHistoryDB               bool
   262  		mimicCrashAfterLedgerCreation bool
   263  	}{
   264  		{
   265  			enableHistoryDB:               true,
   266  			mimicCrashAfterLedgerCreation: true,
   267  		},
   268  		{
   269  			enableHistoryDB:               false,
   270  			mimicCrashAfterLedgerCreation: true,
   271  		},
   272  		{
   273  			enableHistoryDB:               true,
   274  			mimicCrashAfterLedgerCreation: false,
   275  		},
   276  		{
   277  			enableHistoryDB:               false,
   278  			mimicCrashAfterLedgerCreation: false,
   279  		},
   280  	}
   281  
   282  	for i, tc := range testcases {
   283  		t.Run(strconv.Itoa(i), func(t *testing.T) {
   284  			testDeletionOfUnderConstructionLedgersAtStart(t, tc.enableHistoryDB, tc.mimicCrashAfterLedgerCreation)
   285  		})
   286  	}
   287  }
   288  
   289  func testDeletionOfUnderConstructionLedgersAtStart(t *testing.T, enableHistoryDB, mimicCrashAfterLedgerCreation bool) {
   290  	conf, cleanup := testConfig(t)
   291  	conf.HistoryDBConfig.Enabled = enableHistoryDB
   292  	defer cleanup()
   293  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   294  	idStore := provider.idStore
   295  	ledgerID := "testLedger"
   296  	defer func() {
   297  		provider.Close()
   298  	}()
   299  
   300  	switch mimicCrashAfterLedgerCreation {
   301  	case false:
   302  		require.NoError(t,
   303  			idStore.createLedgerID(ledgerID, &msgs.LedgerMetadata{
   304  				Status: msgs.Status_UNDER_CONSTRUCTION,
   305  			}),
   306  		)
   307  	case true:
   308  		genesisBlock, err := configtxtest.MakeGenesisBlock(ledgerID)
   309  		require.NoError(t, err)
   310  		_, err = provider.CreateFromGenesisBlock(genesisBlock)
   311  		require.NoError(t, err)
   312  		m, err := provider.idStore.getLedgerMetadata(ledgerID)
   313  		require.NoError(t, err)
   314  		require.Equal(t, msgs.Status_ACTIVE, m.Status)
   315  		// mimic a situation that a crash happens after ledger creation but before changing the UNDER_CONSTRUCTION status
   316  		// to Status_ACTIVE
   317  		require.NoError(t,
   318  			provider.idStore.updateLedgerStatus(ledgerID, msgs.Status_UNDER_CONSTRUCTION),
   319  		)
   320  	}
   321  	provider.Close()
   322  	// construct a new provider to invoke recovery
   323  	provider = testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   324  	exists, err := provider.Exists(ledgerID)
   325  	require.NoError(t, err)
   326  	require.False(t, exists)
   327  	m, err := provider.idStore.getLedgerMetadata(ledgerID)
   328  	require.NoError(t, err)
   329  	require.Nil(t, m)
   330  }
   331  
   332  func TestLedgerCreationFailure(t *testing.T) {
   333  	conf, cleanup := testConfig(t)
   334  	defer cleanup()
   335  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   336  	ledgerID := "testLedger"
   337  	defer func() {
   338  		provider.Close()
   339  	}()
   340  
   341  	genesisBlock, err := configtxtest.MakeGenesisBlock(ledgerID)
   342  	require.NoError(t, err)
   343  	genesisBlock.Header.Number = 1 // should cause an error during ledger creation
   344  	_, err = provider.CreateFromGenesisBlock(genesisBlock)
   345  	require.EqualError(t, err, "expected block number=0, received block number=1")
   346  
   347  	verifyLedgerDoesNotExist(t, provider, ledgerID)
   348  }
   349  
   350  func TestLedgerCreationFailureDuringLedgerDeletion(t *testing.T) {
   351  	conf, cleanup := testConfig(t)
   352  	defer cleanup()
   353  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   354  	ledgerID := "testLedger"
   355  	defer func() {
   356  		provider.Close()
   357  	}()
   358  
   359  	genesisBlock, err := configtxtest.MakeGenesisBlock(ledgerID)
   360  	require.NoError(t, err)
   361  	genesisBlock.Header.Number = 1 // should cause an error during ledger creation
   362  
   363  	provider.dbProvider.Close()
   364  	_, err = provider.CreateFromGenesisBlock(genesisBlock)
   365  	require.Contains(t, err.Error(), "expected block number=0, received block number=1: error while deleting data from ledger [testLedger]")
   366  
   367  	verifyLedgerIDExists(t, provider, ledgerID, msgs.Status_UNDER_CONSTRUCTION)
   368  }
   369  
   370  func TestMultipleLedgerBasicRW(t *testing.T) {
   371  	conf, cleanup := testConfig(t)
   372  	defer cleanup()
   373  	provider1 := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   374  	defer provider1.Close()
   375  
   376  	numLedgers := 10
   377  	ledgers := make([]ledger.PeerLedger, numLedgers)
   378  	for i := 0; i < numLedgers; i++ {
   379  		bg, gb := testutil.NewBlockGenerator(t, constructTestLedgerID(i), false)
   380  		l, err := provider1.CreateFromGenesisBlock(gb)
   381  		require.NoError(t, err)
   382  		ledgers[i] = l
   383  		txid := util.GenerateUUID()
   384  		s, _ := l.NewTxSimulator(txid)
   385  		err = s.SetState("ns", "testKey", []byte(fmt.Sprintf("testValue_%d", i)))
   386  		s.Done()
   387  		require.NoError(t, err)
   388  		res, err := s.GetTxSimulationResults()
   389  		require.NoError(t, err)
   390  		pubSimBytes, _ := res.GetPubSimulationBytes()
   391  		b := bg.NextBlock([][]byte{pubSimBytes})
   392  		err = l.CommitLegacy(&ledger.BlockAndPvtData{Block: b}, &ledger.CommitOptions{})
   393  		l.Close()
   394  		require.NoError(t, err)
   395  	}
   396  
   397  	provider1.Close()
   398  
   399  	provider2 := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   400  	defer provider2.Close()
   401  	ledgers = make([]ledger.PeerLedger, numLedgers)
   402  	for i := 0; i < numLedgers; i++ {
   403  		l, err := provider2.Open(constructTestLedgerID(i))
   404  		require.NoError(t, err)
   405  		ledgers[i] = l
   406  	}
   407  
   408  	for i, l := range ledgers {
   409  		q, _ := l.NewQueryExecutor()
   410  		val, err := q.GetState("ns", "testKey")
   411  		q.Done()
   412  		require.NoError(t, err)
   413  		require.Equal(t, []byte(fmt.Sprintf("testValue_%d", i)), val)
   414  		l.Close()
   415  	}
   416  }
   417  
   418  func TestLedgerBackup(t *testing.T) {
   419  	ledgerid := "TestLedger"
   420  	basePath, err := ioutil.TempDir("", "kvledger")
   421  	require.NoError(t, err, "Failed to create ledger directory")
   422  	defer os.RemoveAll(basePath)
   423  	originalPath := filepath.Join(basePath, "kvledger1")
   424  	restorePath := filepath.Join(basePath, "kvledger2")
   425  
   426  	// create and populate a ledger in the original environment
   427  	origConf := &ledger.Config{
   428  		RootFSPath:    originalPath,
   429  		StateDBConfig: &ledger.StateDBConfig{},
   430  		PrivateDataConfig: &ledger.PrivateDataConfig{
   431  			MaxBatchSize:                        5000,
   432  			BatchesInterval:                     1000,
   433  			PurgeInterval:                       100,
   434  			DeprioritizedDataReconcilerInterval: 120 * time.Minute,
   435  		},
   436  		HistoryDBConfig: &ledger.HistoryDBConfig{
   437  			Enabled: true,
   438  		},
   439  		SnapshotsConfig: &ledger.SnapshotsConfig{
   440  			RootDir: filepath.Join(originalPath, "snapshots"),
   441  		},
   442  	}
   443  	provider := testutilNewProvider(origConf, t, &mock.DeployedChaincodeInfoProvider{})
   444  	bg, gb := testutil.NewBlockGenerator(t, ledgerid, false)
   445  	gbHash := protoutil.BlockHeaderHash(gb.Header)
   446  	lgr, _ := provider.CreateFromGenesisBlock(gb)
   447  
   448  	txid := util.GenerateUUID()
   449  	simulator, _ := lgr.NewTxSimulator(txid)
   450  	require.NoError(t, simulator.SetState("ns1", "key1", []byte("value1")))
   451  	require.NoError(t, simulator.SetState("ns1", "key2", []byte("value2")))
   452  	require.NoError(t, simulator.SetState("ns1", "key3", []byte("value3")))
   453  	simulator.Done()
   454  	simRes, _ := simulator.GetTxSimulationResults()
   455  	pubSimBytes, _ := simRes.GetPubSimulationBytes()
   456  	block1 := bg.NextBlock([][]byte{pubSimBytes})
   457  	require.NoError(t, lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: block1}, &ledger.CommitOptions{}))
   458  
   459  	txid = util.GenerateUUID()
   460  	simulator, _ = lgr.NewTxSimulator(txid)
   461  	require.NoError(t, simulator.SetState("ns1", "key1", []byte("value4")))
   462  	require.NoError(t, simulator.SetState("ns1", "key2", []byte("value5")))
   463  	require.NoError(t, simulator.SetState("ns1", "key3", []byte("value6")))
   464  	simulator.Done()
   465  	simRes, _ = simulator.GetTxSimulationResults()
   466  	pubSimBytes, _ = simRes.GetPubSimulationBytes()
   467  	block2 := bg.NextBlock([][]byte{pubSimBytes})
   468  	require.NoError(t, lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: block2}, &ledger.CommitOptions{}))
   469  
   470  	lgr.Close()
   471  	provider.Close()
   472  
   473  	// remove the statedb, historydb, and block indexes (they are supposed to be auto created during opening of an existing ledger)
   474  	// and rename the originalPath to restorePath
   475  	require.NoError(t, os.RemoveAll(StateDBPath(originalPath)))
   476  	require.NoError(t, os.RemoveAll(HistoryDBPath(originalPath)))
   477  	require.NoError(t, os.RemoveAll(filepath.Join(BlockStorePath(originalPath), blkstorage.IndexDir)))
   478  	require.NoError(t, os.Rename(originalPath, restorePath))
   479  
   480  	// Instantiate the ledger from restore environment and this should behave exactly as it would have in the original environment
   481  	restoreConf := &ledger.Config{
   482  		RootFSPath:    restorePath,
   483  		StateDBConfig: &ledger.StateDBConfig{},
   484  		PrivateDataConfig: &ledger.PrivateDataConfig{
   485  			MaxBatchSize:                        5000,
   486  			BatchesInterval:                     1000,
   487  			PurgeInterval:                       100,
   488  			DeprioritizedDataReconcilerInterval: 120 * time.Minute,
   489  		},
   490  		HistoryDBConfig: &ledger.HistoryDBConfig{
   491  			Enabled: true,
   492  		},
   493  		SnapshotsConfig: &ledger.SnapshotsConfig{
   494  			RootDir: filepath.Join(restorePath, "snapshots"),
   495  		},
   496  	}
   497  	provider = testutilNewProvider(restoreConf, t, &mock.DeployedChaincodeInfoProvider{})
   498  	defer provider.Close()
   499  
   500  	_, err = provider.CreateFromGenesisBlock(gb)
   501  	require.EqualError(t, err, "ledger [TestLedger] already exists with state [ACTIVE]")
   502  
   503  	lgr, err = provider.Open(ledgerid)
   504  	require.NoError(t, err)
   505  	defer lgr.Close()
   506  
   507  	block1Hash := protoutil.BlockHeaderHash(block1.Header)
   508  	block2Hash := protoutil.BlockHeaderHash(block2.Header)
   509  	bcInfo, _ := lgr.GetBlockchainInfo()
   510  	require.Equal(t, &common.BlockchainInfo{
   511  		Height: 3, CurrentBlockHash: block2Hash, PreviousBlockHash: block1Hash,
   512  	}, bcInfo)
   513  
   514  	b0, _ := lgr.GetBlockByHash(gbHash)
   515  	require.True(t, proto.Equal(b0, gb), "proto messages are not equal")
   516  
   517  	b1, _ := lgr.GetBlockByHash(block1Hash)
   518  	require.True(t, proto.Equal(b1, block1), "proto messages are not equal")
   519  
   520  	b2, _ := lgr.GetBlockByHash(block2Hash)
   521  	require.True(t, proto.Equal(b2, block2), "proto messages are not equal")
   522  
   523  	b0, _ = lgr.GetBlockByNumber(0)
   524  	require.True(t, proto.Equal(b0, gb), "proto messages are not equal")
   525  
   526  	b1, _ = lgr.GetBlockByNumber(1)
   527  	require.True(t, proto.Equal(b1, block1), "proto messages are not equal")
   528  
   529  	b2, _ = lgr.GetBlockByNumber(2)
   530  	require.True(t, proto.Equal(b2, block2), "proto messages are not equal")
   531  
   532  	// get the tran id from the 2nd block, then use it to test GetTransactionByID()
   533  	txEnvBytes2 := block1.Data.Data[0]
   534  	txEnv2, err := protoutil.GetEnvelopeFromBlock(txEnvBytes2)
   535  	require.NoError(t, err, "Error upon GetEnvelopeFromBlock")
   536  	payload2, err := protoutil.UnmarshalPayload(txEnv2.Payload)
   537  	require.NoError(t, err, "Error upon GetPayload")
   538  	chdr, err := protoutil.UnmarshalChannelHeader(payload2.Header.ChannelHeader)
   539  	require.NoError(t, err, "Error upon GetChannelHeaderFromBytes")
   540  	txID2 := chdr.TxId
   541  	processedTran2, err := lgr.GetTransactionByID(txID2)
   542  	require.NoError(t, err, "Error upon GetTransactionByID")
   543  	// get the tran envelope from the retrieved ProcessedTransaction
   544  	retrievedTxEnv2 := processedTran2.TransactionEnvelope
   545  	require.Equal(t, txEnv2, retrievedTxEnv2)
   546  
   547  	qe, _ := lgr.NewQueryExecutor()
   548  	value1, _ := qe.GetState("ns1", "key1")
   549  	require.Equal(t, []byte("value4"), value1)
   550  
   551  	hqe, err := lgr.NewHistoryQueryExecutor()
   552  	require.NoError(t, err)
   553  	itr, err := hqe.GetHistoryForKey("ns1", "key1")
   554  	require.NoError(t, err)
   555  	defer itr.Close()
   556  
   557  	result1, err := itr.Next()
   558  	require.NoError(t, err)
   559  	require.Equal(t, []byte("value4"), result1.(*queryresult.KeyModification).Value)
   560  	result2, err := itr.Next()
   561  	require.NoError(t, err)
   562  	require.Equal(t, []byte("value1"), result2.(*queryresult.KeyModification).Value)
   563  }
   564  
   565  func constructTestLedgerID(i int) string {
   566  	return fmt.Sprintf("ledger_%06d", i)
   567  }
   568  
   569  func constructTestLedger(t *testing.T, provider *Provider, sequenceID int) string {
   570  	ledgerID := constructTestLedgerID(sequenceID)
   571  	gb, err := configtxtest.MakeGenesisBlock(ledgerID)
   572  	require.NoError(t, err)
   573  	require.NotNil(t, gb)
   574  
   575  	lgr, err := provider.CreateFromGenesisBlock(gb)
   576  	require.NoError(t, err)
   577  	require.NotNil(t, lgr)
   578  
   579  	return ledgerID
   580  }
   581  
   582  func testConfig(t *testing.T) (conf *ledger.Config, cleanup func()) {
   583  	path, err := ioutil.TempDir("", "kvledger")
   584  	require.NoError(t, err, "Failed to create test ledger directory")
   585  	conf = &ledger.Config{
   586  		RootFSPath:    path,
   587  		StateDBConfig: &ledger.StateDBConfig{},
   588  		PrivateDataConfig: &ledger.PrivateDataConfig{
   589  			MaxBatchSize:                        5000,
   590  			BatchesInterval:                     1000,
   591  			PurgeInterval:                       100,
   592  			DeprioritizedDataReconcilerInterval: 120 * time.Minute,
   593  		},
   594  		HistoryDBConfig: &ledger.HistoryDBConfig{
   595  			Enabled: true,
   596  		},
   597  		SnapshotsConfig: &ledger.SnapshotsConfig{
   598  			RootDir: filepath.Join(path, "snapshots"),
   599  		},
   600  	}
   601  	cleanup = func() {
   602  		os.RemoveAll(path)
   603  	}
   604  
   605  	return conf, cleanup
   606  }
   607  
   608  func testutilNewProvider(conf *ledger.Config, t *testing.T, ccInfoProvider *mock.DeployedChaincodeInfoProvider) *Provider {
   609  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   610  	require.NoError(t, err)
   611  
   612  	provider, err := NewProvider(
   613  		&ledger.Initializer{
   614  			DeployedChaincodeInfoProvider:   ccInfoProvider,
   615  			MetricsProvider:                 &disabled.Provider{},
   616  			Config:                          conf,
   617  			HashProvider:                    cryptoProvider,
   618  			HealthCheckRegistry:             &mock.HealthCheckRegistry{},
   619  			ChaincodeLifecycleEventProvider: &mock.ChaincodeLifecycleEventProvider{},
   620  			MembershipInfoProvider:          &mock.MembershipInfoProvider{},
   621  		},
   622  	)
   623  	require.NoError(t, err, "Failed to create new Provider")
   624  	return provider
   625  }
   626  
   627  type nsCollBtlConfig struct {
   628  	namespace string
   629  	btlConfig map[string]uint64
   630  }
   631  
   632  func testutilNewProviderWithCollectionConfig(
   633  	t *testing.T,
   634  	nsCollBtlConfigs []*nsCollBtlConfig,
   635  	conf *ledger.Config,
   636  ) *Provider {
   637  	provider := testutilNewProvider(conf, t, &mock.DeployedChaincodeInfoProvider{})
   638  	mockCCInfoProvider := provider.initializer.DeployedChaincodeInfoProvider.(*mock.DeployedChaincodeInfoProvider)
   639  	collectionConfPkgs := []*peer.CollectionConfigPackage{}
   640  
   641  	nsCollMap := map[string]map[string]*peer.StaticCollectionConfig{}
   642  	for _, nsCollBtlConf := range nsCollBtlConfigs {
   643  		collMap := map[string]*peer.StaticCollectionConfig{}
   644  		var collConf []*peer.CollectionConfig
   645  		for collName, btl := range nsCollBtlConf.btlConfig {
   646  			staticConf := &peer.StaticCollectionConfig{Name: collName, BlockToLive: btl}
   647  			collMap[collName] = staticConf
   648  			collectionConf := &peer.CollectionConfig{}
   649  			collectionConf.Payload = &peer.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: staticConf}
   650  			collConf = append(collConf, collectionConf)
   651  		}
   652  		collectionConfPkgs = append(collectionConfPkgs, &peer.CollectionConfigPackage{Config: collConf})
   653  		nsCollMap[nsCollBtlConf.namespace] = collMap
   654  	}
   655  
   656  	mockCCInfoProvider.ChaincodeInfoStub = func(channelName, ccName string, qe ledger.SimpleQueryExecutor) (*ledger.DeployedChaincodeInfo, error) {
   657  		for i, nsCollBtlConf := range nsCollBtlConfigs {
   658  			if ccName == nsCollBtlConf.namespace {
   659  				return &ledger.DeployedChaincodeInfo{
   660  					Name: nsCollBtlConf.namespace, ExplicitCollectionConfigPkg: collectionConfPkgs[i],
   661  				}, nil
   662  			}
   663  		}
   664  		return nil, nil
   665  	}
   666  
   667  	mockCCInfoProvider.AllCollectionsConfigPkgStub = func(channelName, ccName string, qe ledger.SimpleQueryExecutor) (*peer.CollectionConfigPackage, error) {
   668  		for i, nsCollBtlConf := range nsCollBtlConfigs {
   669  			if ccName == nsCollBtlConf.namespace {
   670  				return collectionConfPkgs[i], nil
   671  			}
   672  		}
   673  		return nil, nil
   674  	}
   675  
   676  	mockCCInfoProvider.CollectionInfoStub = func(channelName, ccName, collName string, qe ledger.SimpleQueryExecutor) (*peer.StaticCollectionConfig, error) {
   677  		for _, nsCollBtlConf := range nsCollBtlConfigs {
   678  			if ccName == nsCollBtlConf.namespace {
   679  				return nsCollMap[nsCollBtlConf.namespace][collName], nil
   680  			}
   681  		}
   682  		return nil, nil
   683  	}
   684  	return provider
   685  }
   686  
   687  func verifyLedgerDoesNotExist(t *testing.T, provider *Provider, ledgerID string) {
   688  	exists, err := provider.idStore.ledgerIDExists(ledgerID)
   689  	require.NoError(t, err)
   690  	require.False(t, exists)
   691  
   692  	metadata, err := provider.idStore.getLedgerMetadata(ledgerID)
   693  	require.NoError(t, err)
   694  	require.Nil(t, metadata)
   695  
   696  	activeLedgerIDs, err := provider.List()
   697  	require.NoError(t, err)
   698  	require.NotContains(t, activeLedgerIDs, ledgerID)
   699  
   700  	exists, err = provider.blkStoreProvider.Exists(ledgerID)
   701  	require.NoError(t, err)
   702  	require.False(t, exists)
   703  
   704  	db, err := provider.dbProvider.GetDBHandle(ledgerID, nil)
   705  	require.NoError(t, err)
   706  	itr, err := db.GetFullScanIterator(func(string) bool { return false })
   707  	require.NoError(t, err)
   708  	kv, err := itr.Next()
   709  	require.NoError(t, err)
   710  	require.Nil(t, kv)
   711  	sp, err := db.GetLatestSavePoint()
   712  	require.NoError(t, err)
   713  	require.Nil(t, sp)
   714  
   715  	historydb := provider.historydbProvider.GetDBHandle(ledgerID)
   716  	sp, err = historydb.GetLastSavepoint()
   717  	require.NoError(t, err)
   718  	require.Nil(t, sp)
   719  }
   720  
   721  func verifyLedgerIDExists(t *testing.T, provider *Provider, ledgerID string, expectedStatus msgs.Status) {
   722  	exists, err := provider.idStore.ledgerIDExists(ledgerID)
   723  	require.NoError(t, err)
   724  	require.True(t, exists)
   725  
   726  	metadata, err := provider.idStore.getLedgerMetadata(ledgerID)
   727  	require.NoError(t, err)
   728  	require.Equal(t, metadata.Status, expectedStatus)
   729  }