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 }