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

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package tests
     8  
     9  import (
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/osdi23p228/fabric/bccsp"
    19  	"github.com/osdi23p228/fabric/bccsp/sw"
    20  	"github.com/osdi23p228/fabric/common/ledger/blkstorage"
    21  	"github.com/osdi23p228/fabric/common/ledger/util"
    22  	"github.com/osdi23p228/fabric/common/metrics/disabled"
    23  	"github.com/osdi23p228/fabric/core/chaincode/lifecycle"
    24  	"github.com/osdi23p228/fabric/core/common/privdata"
    25  	"github.com/osdi23p228/fabric/core/container/externalbuilder"
    26  	"github.com/osdi23p228/fabric/core/ledger"
    27  	"github.com/osdi23p228/fabric/core/ledger/kvledger"
    28  	"github.com/osdi23p228/fabric/core/ledger/ledgermgmt"
    29  	corepeer "github.com/osdi23p228/fabric/core/peer"
    30  	"github.com/osdi23p228/fabric/core/scc/lscc"
    31  	"github.com/osdi23p228/fabric/internal/fileutil"
    32  	"github.com/osdi23p228/fabric/msp"
    33  	"github.com/osdi23p228/fabric/msp/mgmt"
    34  	"github.com/osdi23p228/fabric/protoutil"
    35  	"github.com/stretchr/testify/assert"
    36  )
    37  
    38  type rebuildable uint8
    39  
    40  const (
    41  	rebuildableStatedb       rebuildable = 1
    42  	rebuildableBlockIndex    rebuildable = 2
    43  	rebuildableConfigHistory rebuildable = 4
    44  	rebuildableHistoryDB     rebuildable = 8
    45  	rebuildableBookkeeper    rebuildable = 16
    46  )
    47  
    48  type env struct {
    49  	assert      *assert.Assertions
    50  	initializer *ledgermgmt.Initializer
    51  	ledgerMgr   *ledgermgmt.LedgerMgr
    52  }
    53  
    54  func newEnv(t *testing.T) *env {
    55  	cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    56  	assert.NoError(t, err)
    57  	return newEnvWithInitializer(t, &ledgermgmt.Initializer{
    58  		HashProvider: cryptoProvider,
    59  		EbMetadataProvider: &externalbuilder.MetadataProvider{
    60  			DurablePath: "testdata",
    61  		},
    62  	})
    63  }
    64  
    65  func newEnvWithInitializer(t *testing.T, initializer *ledgermgmt.Initializer) *env {
    66  	populateMissingsWithTestDefaults(t, initializer)
    67  
    68  	return &env{
    69  		assert:      assert.New(t),
    70  		initializer: initializer,
    71  	}
    72  }
    73  
    74  func (e *env) cleanup() {
    75  	if e.ledgerMgr != nil {
    76  		e.ledgerMgr.Close()
    77  	}
    78  	// Ignore RemoveAll error because when a test mounts a dir to a couchdb container,
    79  	// the mounted dir cannot be deleted in CI builds. This has no impact to CI because it gets a new VM for each build.
    80  	// When running the test locally (macOS and linux VM), the mounted dirs are deleted without any error.
    81  	os.RemoveAll(e.initializer.Config.RootFSPath)
    82  }
    83  
    84  func (e *env) closeAllLedgersAndRemoveDirContents(flags rebuildable) {
    85  	if e.ledgerMgr != nil {
    86  		e.ledgerMgr.Close()
    87  	}
    88  	defer e.initLedgerMgmt()
    89  
    90  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
    91  		indexPath := e.getBlockIndexDBPath()
    92  		logger.Infof("Deleting blockstore indexdb path [%s]", indexPath)
    93  		e.verifyNonEmptyDirExists(indexPath)
    94  		e.assert.NoError(fileutil.RemoveContents(indexPath))
    95  	}
    96  
    97  	if flags&rebuildableStatedb == rebuildableStatedb {
    98  		statedbPath := e.getLevelstateDBPath()
    99  		logger.Infof("Deleting statedb path [%s]", statedbPath)
   100  		e.verifyNonEmptyDirExists(statedbPath)
   101  		e.assert.NoError(fileutil.RemoveContents(statedbPath))
   102  	}
   103  
   104  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   105  		configHistoryPath := e.getConfigHistoryDBPath()
   106  		logger.Infof("Deleting configHistory db path [%s]", configHistoryPath)
   107  		e.verifyNonEmptyDirExists(configHistoryPath)
   108  		e.assert.NoError(fileutil.RemoveContents(configHistoryPath))
   109  	}
   110  
   111  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   112  		bookkeeperPath := e.getBookkeeperDBPath()
   113  		logger.Infof("Deleting bookkeeper db path [%s]", bookkeeperPath)
   114  		e.verifyNonEmptyDirExists(bookkeeperPath)
   115  		e.assert.NoError(fileutil.RemoveContents(bookkeeperPath))
   116  	}
   117  
   118  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   119  		historyPath := e.getHistoryDBPath()
   120  		logger.Infof("Deleting history db path [%s]", historyPath)
   121  		e.verifyNonEmptyDirExists(historyPath)
   122  		e.assert.NoError(fileutil.RemoveContents(historyPath))
   123  	}
   124  
   125  	e.verifyRebuilableDirEmpty(flags)
   126  }
   127  
   128  func (e *env) verifyRebuilablesExist(flags rebuildable) {
   129  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
   130  		e.verifyNonEmptyDirExists(e.getBlockIndexDBPath())
   131  	}
   132  	if flags&rebuildableStatedb == rebuildableStatedb {
   133  		e.verifyNonEmptyDirExists(e.getLevelstateDBPath())
   134  	}
   135  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   136  		e.verifyNonEmptyDirExists(e.getConfigHistoryDBPath())
   137  	}
   138  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   139  		e.verifyNonEmptyDirExists(e.getBookkeeperDBPath())
   140  	}
   141  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   142  		e.verifyNonEmptyDirExists(e.getHistoryDBPath())
   143  	}
   144  }
   145  
   146  func (e *env) verifyRebuilableDirEmpty(flags rebuildable) {
   147  	if flags&rebuildableStatedb == rebuildableStatedb {
   148  		e.verifyDirEmpty(e.getLevelstateDBPath())
   149  	}
   150  	if flags&rebuildableBlockIndex == rebuildableBlockIndex {
   151  		e.verifyDirEmpty(e.getBlockIndexDBPath())
   152  	}
   153  	if flags&rebuildableConfigHistory == rebuildableConfigHistory {
   154  		e.verifyDirEmpty(e.getConfigHistoryDBPath())
   155  	}
   156  	if flags&rebuildableBookkeeper == rebuildableBookkeeper {
   157  		e.verifyDirEmpty(e.getBookkeeperDBPath())
   158  	}
   159  	if flags&rebuildableHistoryDB == rebuildableHistoryDB {
   160  		e.verifyDirEmpty(e.getHistoryDBPath())
   161  	}
   162  }
   163  
   164  func (e *env) verifyNonEmptyDirExists(path string) {
   165  	empty, err := util.DirEmpty(path)
   166  	e.assert.NoError(err)
   167  	e.assert.False(empty)
   168  }
   169  
   170  func (e *env) verifyDirEmpty(path string) {
   171  	empty, err := util.DirEmpty(path)
   172  	e.assert.NoError(err)
   173  	e.assert.True(empty)
   174  }
   175  
   176  func (e *env) initLedgerMgmt() {
   177  	e.ledgerMgr = ledgermgmt.NewLedgerMgr(e.initializer)
   178  }
   179  
   180  func (e *env) closeLedgerMgmt() {
   181  	e.ledgerMgr.Close()
   182  }
   183  
   184  func (e *env) getLevelstateDBPath() string {
   185  	return kvledger.StateDBPath(e.initializer.Config.RootFSPath)
   186  }
   187  
   188  func (e *env) getBlockIndexDBPath() string {
   189  	return filepath.Join(kvledger.BlockStorePath(e.initializer.Config.RootFSPath), blkstorage.IndexDir)
   190  }
   191  
   192  func (e *env) getConfigHistoryDBPath() string {
   193  	return kvledger.ConfigHistoryDBPath(e.initializer.Config.RootFSPath)
   194  }
   195  
   196  func (e *env) getHistoryDBPath() string {
   197  	return kvledger.HistoryDBPath(e.initializer.Config.RootFSPath)
   198  }
   199  
   200  func (e *env) getBookkeeperDBPath() string {
   201  	return kvledger.BookkeeperDBPath(e.initializer.Config.RootFSPath)
   202  }
   203  
   204  func populateMissingsWithTestDefaults(t *testing.T, initializer *ledgermgmt.Initializer) {
   205  	if initializer.CustomTxProcessors == nil {
   206  		initializer.CustomTxProcessors = map[common.HeaderType]ledger.CustomTxProcessor{}
   207  	}
   208  
   209  	if initializer.DeployedChaincodeInfoProvider == nil {
   210  		initializer.DeployedChaincodeInfoProvider = &lscc.DeployedCCInfoProvider{}
   211  	}
   212  
   213  	if initializer.MembershipInfoProvider == nil {
   214  		identityDeserializerFactory := func(chainID string) msp.IdentityDeserializer {
   215  			return mgmt.GetManagerForChain(chainID)
   216  		}
   217  		cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
   218  		assert.NoError(t, err)
   219  		mspID := "test-mspid"
   220  		membershipInfoProvider := privdata.NewMembershipInfoProvider(mspID, createSelfSignedData(cryptoProvider), identityDeserializerFactory)
   221  		initializer.MembershipInfoProvider = membershipInfoProvider
   222  	}
   223  
   224  	if initializer.MetricsProvider == nil {
   225  		initializer.MetricsProvider = &disabled.Provider{}
   226  	}
   227  
   228  	if initializer.Config == nil || initializer.Config.RootFSPath == "" {
   229  		rootPath, err := ioutil.TempDir("/tmp", "ledgersData")
   230  		if err != nil {
   231  			t.Fatalf("Failed to create root directory: %s", err)
   232  		}
   233  
   234  		initializer.Config = &ledger.Config{
   235  			RootFSPath: rootPath,
   236  		}
   237  	}
   238  
   239  	if initializer.Config.StateDBConfig == nil {
   240  		initializer.Config.StateDBConfig = &ledger.StateDBConfig{
   241  			StateDatabase: "goleveldb",
   242  		}
   243  	}
   244  
   245  	if initializer.Config.HistoryDBConfig == nil {
   246  		initializer.Config.HistoryDBConfig = &ledger.HistoryDBConfig{
   247  			Enabled: true,
   248  		}
   249  	}
   250  
   251  	if initializer.Config.PrivateDataConfig == nil {
   252  		initializer.Config.PrivateDataConfig = &ledger.PrivateDataConfig{
   253  			MaxBatchSize:                        5000,
   254  			BatchesInterval:                     1000,
   255  			PurgeInterval:                       100,
   256  			DeprioritizedDataReconcilerInterval: 120 * time.Minute,
   257  		}
   258  	}
   259  	if initializer.Config.SnapshotsConfig == nil {
   260  		initializer.Config.SnapshotsConfig = &ledger.SnapshotsConfig{
   261  			RootDir: filepath.Join(initializer.Config.RootFSPath, "snapshots"),
   262  		}
   263  	}
   264  }
   265  
   266  func createSelfSignedData(cryptoProvider bccsp.BCCSP) protoutil.SignedData {
   267  	sID := mgmt.GetLocalSigningIdentityOrPanic(cryptoProvider)
   268  	msg := make([]byte, 32)
   269  	sig, err := sID.Sign(msg)
   270  	if err != nil {
   271  		logger.Panicf("Failed creating self signed data because message signing failed: %v", err)
   272  	}
   273  	peerIdentity, err := sID.Serialize()
   274  	if err != nil {
   275  		logger.Panicf("Failed creating self signed data because peer identity couldn't be serialized: %v", err)
   276  	}
   277  	return protoutil.SignedData{
   278  		Data:      msg,
   279  		Signature: sig,
   280  		Identity:  peerIdentity,
   281  	}
   282  }
   283  
   284  // deployedCCInfoProviderWrapper is a wrapper type that overrides ChaincodeImplicitCollections
   285  type deployedCCInfoProviderWrapper struct {
   286  	*lifecycle.ValidatorCommitter
   287  	orgMSPIDs []string
   288  }
   289  
   290  // AllCollectionsConfigPkg overrides the same method in lifecycle.AllCollectionsConfigPkg.
   291  // It is basically a copy of lifecycle.AllCollectionsConfigPkg and invokes ImplicitCollections in the wrapper.
   292  // This method is called when the unit test code gets private data code path.
   293  func (dc *deployedCCInfoProviderWrapper) AllCollectionsConfigPkg(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) (*peer.CollectionConfigPackage, error) {
   294  	chaincodeInfo, err := dc.ChaincodeInfo(channelName, chaincodeName, qe)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  	explicitCollectionConfigPkg := chaincodeInfo.ExplicitCollectionConfigPkg
   299  
   300  	implicitCollections, _ := dc.ImplicitCollections(channelName, "", nil)
   301  
   302  	var combinedColls []*peer.CollectionConfig
   303  	if explicitCollectionConfigPkg != nil {
   304  		combinedColls = append(combinedColls, explicitCollectionConfigPkg.Config...)
   305  	}
   306  	for _, implicitColl := range implicitCollections {
   307  		c := &peer.CollectionConfig{}
   308  		c.Payload = &peer.CollectionConfig_StaticCollectionConfig{StaticCollectionConfig: implicitColl}
   309  		combinedColls = append(combinedColls, c)
   310  	}
   311  	return &peer.CollectionConfigPackage{
   312  		Config: combinedColls,
   313  	}, nil
   314  }
   315  
   316  // ImplicitCollections overrides the same method in lifecycle.ValidatorCommitter.
   317  // It constructs static collection config using known mspids from the sample ledger.
   318  // This method is called when the unit test code gets collection configuration.
   319  func (dc *deployedCCInfoProviderWrapper) ImplicitCollections(channelName, chaincodeName string, qe ledger.SimpleQueryExecutor) ([]*peer.StaticCollectionConfig, error) {
   320  	collConfigs := make([]*peer.StaticCollectionConfig, 0, len(dc.orgMSPIDs))
   321  	for _, mspID := range dc.orgMSPIDs {
   322  		collConfigs = append(collConfigs, dc.ValidatorCommitter.GenerateImplicitCollectionForOrg(mspID))
   323  	}
   324  	return collConfigs, nil
   325  }
   326  
   327  func createDeployedCCInfoProvider(orgMSPIDs []string) ledger.DeployedChaincodeInfoProvider {
   328  	deployedCCInfoProvider := &lifecycle.ValidatorCommitter{
   329  		CoreConfig: &corepeer.Config{},
   330  		Resources: &lifecycle.Resources{
   331  			Serializer: &lifecycle.Serializer{},
   332  		},
   333  		LegacyDeployedCCInfoProvider: &lscc.DeployedCCInfoProvider{},
   334  	}
   335  	return &deployedCCInfoProviderWrapper{
   336  		ValidatorCommitter: deployedCCInfoProvider,
   337  		orgMSPIDs:          orgMSPIDs,
   338  	}
   339  }