github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/ledgermgmt/ledger_mgmt.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ledgermgmt 8 9 import ( 10 "bytes" 11 "fmt" 12 "sync" 13 14 "github.com/hechain20/hechain/common/flogging" 15 "github.com/hechain20/hechain/common/metrics" 16 "github.com/hechain20/hechain/core/common/ccprovider" 17 "github.com/hechain20/hechain/core/ledger" 18 "github.com/hechain20/hechain/core/ledger/cceventmgmt" 19 "github.com/hechain20/hechain/core/ledger/kvledger" 20 "github.com/hechain20/hechain/internal/fileutil" 21 "github.com/hyperledger/fabric-protos-go/common" 22 pb "github.com/hyperledger/fabric-protos-go/peer" 23 "github.com/pkg/errors" 24 ) 25 26 var logger = flogging.MustGetLogger("ledgermgmt") 27 28 // ErrLedgerAlreadyOpened is thrown by a CreateLedger call if a ledger with the given id is already opened 29 var ErrLedgerAlreadyOpened = errors.New("ledger already opened") 30 31 // ErrLedgerMgmtNotInitialized is thrown when ledger mgmt is used before initializing this 32 var ErrLedgerMgmtNotInitialized = errors.New("ledger mgmt should be initialized before using") 33 34 // LedgerMgr manages ledgers for all channels 35 type LedgerMgr struct { 36 creationLock sync.Mutex 37 joinBySnapshotStatus *pb.JoinBySnapshotStatus 38 39 lock sync.Mutex 40 openedLedgers map[string]ledger.PeerLedger 41 ledgerProvider ledger.PeerLedgerProvider 42 43 ebMetadataProvider MetadataProvider 44 } 45 46 type MetadataProvider interface { 47 PackageMetadata(ccid string) ([]byte, error) 48 } 49 50 // Initializer encapsulates all the external dependencies for the ledger module 51 type Initializer struct { 52 CustomTxProcessors map[common.HeaderType]ledger.CustomTxProcessor 53 StateListeners []ledger.StateListener 54 DeployedChaincodeInfoProvider ledger.DeployedChaincodeInfoProvider 55 MembershipInfoProvider ledger.MembershipInfoProvider 56 ChaincodeLifecycleEventProvider ledger.ChaincodeLifecycleEventProvider 57 MetricsProvider metrics.Provider 58 HealthCheckRegistry ledger.HealthCheckRegistry 59 Config *ledger.Config 60 HashProvider ledger.HashProvider 61 EbMetadataProvider MetadataProvider 62 } 63 64 // NewLedgerMgr creates a new LedgerMgr 65 func NewLedgerMgr(initializer *Initializer) *LedgerMgr { 66 logger.Info("Initializing LedgerMgr") 67 finalStateListeners := addListenerForCCEventsHandler( 68 initializer.DeployedChaincodeInfoProvider, 69 initializer.StateListeners, 70 ) 71 provider, err := kvledger.NewProvider( 72 &ledger.Initializer{ 73 StateListeners: finalStateListeners, 74 DeployedChaincodeInfoProvider: initializer.DeployedChaincodeInfoProvider, 75 MembershipInfoProvider: initializer.MembershipInfoProvider, 76 ChaincodeLifecycleEventProvider: initializer.ChaincodeLifecycleEventProvider, 77 MetricsProvider: initializer.MetricsProvider, 78 HealthCheckRegistry: initializer.HealthCheckRegistry, 79 Config: initializer.Config, 80 CustomTxProcessors: initializer.CustomTxProcessors, 81 HashProvider: initializer.HashProvider, 82 }, 83 ) 84 if err != nil { 85 panic(fmt.Sprintf("Error in instantiating ledger provider: %+v", err)) 86 } 87 ledgerMgr := &LedgerMgr{ 88 joinBySnapshotStatus: &pb.JoinBySnapshotStatus{}, 89 openedLedgers: make(map[string]ledger.PeerLedger), 90 ledgerProvider: provider, 91 ebMetadataProvider: initializer.EbMetadataProvider, 92 } 93 // TODO remove the following package level init 94 cceventmgmt.Initialize(&chaincodeInfoProviderImpl{ 95 ledgerMgr, 96 initializer.DeployedChaincodeInfoProvider, 97 }) 98 logger.Info("Initialized LedgerMgr") 99 return ledgerMgr 100 } 101 102 // CreateLedger creates a new ledger with the given genesis block. 103 // This function guarantees that the creation of ledger and committing the genesis block would an atomic action. 104 // The channel id retrieved from the genesis block is treated as a ledger id. 105 // It returns an error if another ledger is being created from a snapshot. 106 func (m *LedgerMgr) CreateLedger(id string, genesisBlock *common.Block) (ledger.PeerLedger, error) { 107 m.creationLock.Lock() 108 defer m.creationLock.Unlock() 109 110 if m.joinBySnapshotStatus.InProgress { 111 return nil, errors.Errorf("a ledger is being created from a snapshot at %s. Call ledger creation again after it is done.", m.joinBySnapshotStatus.BootstrappingSnapshotDir) 112 } 113 114 m.lock.Lock() 115 defer m.lock.Unlock() 116 logger.Infof("Creating ledger [%s] with genesis block", id) 117 l, err := m.ledgerProvider.CreateFromGenesisBlock(genesisBlock) 118 if err != nil { 119 return nil, err 120 } 121 m.openedLedgers[id] = l 122 logger.Infof("Created ledger [%s] with genesis block", id) 123 return &closableLedger{ 124 ledgerMgr: m, 125 id: id, 126 PeerLedger: l, 127 }, nil 128 } 129 130 // CreateLedgerFromSnapshot creates a new ledger with the given snapshot and executes the callback function 131 // after the ledger is created. This function launches to goroutine to create the ledger and call the callback func. 132 // All ledger dbs would be created in an atomic action. The channel id retrieved from the snapshot metadata 133 // is treated as a ledger id. It returns an error if another ledger is being created from a snapshot. 134 func (m *LedgerMgr) CreateLedgerFromSnapshot(snapshotDir string, channelCallback func(ledger.PeerLedger, string)) error { 135 // verify snapshotDir exists and is not empty 136 empty, err := fileutil.DirEmpty(snapshotDir) 137 if err != nil { 138 return err 139 } 140 if empty { 141 return errors.Errorf("snapshot dir %s is empty", snapshotDir) 142 } 143 144 if err := m.setJoinBySnapshotStatus(snapshotDir); err != nil { 145 return err 146 } 147 148 go func() { 149 defer m.resetJoinBySnapshotStatus() 150 151 ledger, cid, err := m.createFromSnapshot(snapshotDir) 152 if err != nil { 153 logger.Errorw("Error creating ledger from snapshot", "snapshotDir", snapshotDir, "error", err) 154 return 155 } 156 157 channelCallback(ledger, cid) 158 }() 159 160 return nil 161 } 162 163 func (m *LedgerMgr) createFromSnapshot(snapshotDir string) (ledger.PeerLedger, string, error) { 164 m.lock.Lock() 165 defer m.lock.Unlock() 166 logger.Infof("Creating ledger from snapshot at %s", snapshotDir) 167 l, cid, err := m.ledgerProvider.CreateFromSnapshot(snapshotDir) 168 if err != nil { 169 return nil, "", err 170 } 171 m.openedLedgers[cid] = l 172 logger.Infof("Created ledger [%s] from snapshot", cid) 173 return &closableLedger{ 174 ledgerMgr: m, 175 id: cid, 176 PeerLedger: l, 177 }, cid, nil 178 } 179 180 // setJoinBySnapshotStatus sets joinBySnapshotStatus to indicate a CreateLedgerFromSnapshot is in-progress 181 // so that other CreateLedger or CreateLedgerFromSnapshot calls will not be allowed. 182 func (m *LedgerMgr) setJoinBySnapshotStatus(snapshotDir string) error { 183 m.creationLock.Lock() 184 defer m.creationLock.Unlock() 185 if m.joinBySnapshotStatus.InProgress { 186 return errors.Errorf("a ledger is being created from a snapshot at %s. Call ledger creation again after it is done.", m.joinBySnapshotStatus.BootstrappingSnapshotDir) 187 } 188 m.joinBySnapshotStatus.InProgress = true 189 m.joinBySnapshotStatus.BootstrappingSnapshotDir = snapshotDir 190 return nil 191 } 192 193 // resetJoinBySnapshotStatus resets joinBySnapshotStatus to indicate no CreateLedgerFromSnapshot is in-progress 194 // so that other CreateLedger or CreateLedgerFromSnapshot calls will be allowed. 195 func (m *LedgerMgr) resetJoinBySnapshotStatus() { 196 m.creationLock.Lock() 197 defer m.creationLock.Unlock() 198 m.joinBySnapshotStatus.InProgress = false 199 m.joinBySnapshotStatus.BootstrappingSnapshotDir = "" 200 } 201 202 // OpenLedger returns a ledger for the given id 203 func (m *LedgerMgr) OpenLedger(id string) (ledger.PeerLedger, error) { 204 logger.Infof("Opening ledger with id = %s", id) 205 m.lock.Lock() 206 defer m.lock.Unlock() 207 _, ok := m.openedLedgers[id] 208 if ok { 209 return nil, ErrLedgerAlreadyOpened 210 } 211 l, err := m.ledgerProvider.Open(id) 212 if err != nil { 213 return nil, err 214 } 215 m.openedLedgers[id] = l 216 logger.Infof("Opened ledger with id = %s", id) 217 return &closableLedger{ 218 ledgerMgr: m, 219 id: id, 220 PeerLedger: l, 221 }, nil 222 } 223 224 // GetLedgerIDs returns the ids of the ledgers created 225 func (m *LedgerMgr) GetLedgerIDs() ([]string, error) { 226 m.lock.Lock() 227 defer m.lock.Unlock() 228 return m.ledgerProvider.List() 229 } 230 231 // JoinBySnapshotStatus returns the status of joinbysnapshot which includes 232 // ledger creation and channel callback. 233 func (m *LedgerMgr) JoinBySnapshotStatus() *pb.JoinBySnapshotStatus { 234 m.creationLock.Lock() 235 defer m.creationLock.Unlock() 236 // return a copy of joinBySnapshotStatus to the caller 237 return &pb.JoinBySnapshotStatus{ 238 InProgress: m.joinBySnapshotStatus.InProgress, 239 BootstrappingSnapshotDir: m.joinBySnapshotStatus.BootstrappingSnapshotDir, 240 } 241 } 242 243 // Close closes all the opened ledgers and any resources held for ledger management 244 func (m *LedgerMgr) Close() { 245 logger.Infof("Closing ledger mgmt") 246 m.lock.Lock() 247 defer m.lock.Unlock() 248 for _, l := range m.openedLedgers { 249 l.Close() 250 } 251 m.ledgerProvider.Close() 252 m.openedLedgers = nil 253 logger.Infof("ledger mgmt closed") 254 } 255 256 func (m *LedgerMgr) getOpenedLedger(ledgerID string) (ledger.PeerLedger, error) { 257 m.lock.Lock() 258 defer m.lock.Unlock() 259 l, ok := m.openedLedgers[ledgerID] 260 if !ok { 261 return nil, errors.Errorf("Ledger not opened [%s]", ledgerID) 262 } 263 return l, nil 264 } 265 266 func (m *LedgerMgr) closeLedger(ledgerID string) { 267 m.lock.Lock() 268 defer m.lock.Unlock() 269 l, ok := m.openedLedgers[ledgerID] 270 if ok { 271 l.Close() 272 delete(m.openedLedgers, ledgerID) 273 } 274 } 275 276 // closableLedger extends from actual validated ledger and overwrites the Close method 277 type closableLedger struct { 278 ledgerMgr *LedgerMgr 279 id string 280 ledger.PeerLedger 281 } 282 283 // Close closes the actual ledger and removes the entries from opened ledgers map 284 func (l *closableLedger) Close() { 285 l.ledgerMgr.closeLedger(l.id) 286 } 287 288 // lscc namespace listener for chaincode instantiate transactions (which manipulates data in 'lscc' namespace) 289 // this code should be later moved to peer and passed via `Initialize` function of ledgermgmt 290 func addListenerForCCEventsHandler( 291 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 292 stateListeners []ledger.StateListener) []ledger.StateListener { 293 return append(stateListeners, &cceventmgmt.KVLedgerLSCCStateListener{DeployedChaincodeInfoProvider: deployedCCInfoProvider}) 294 } 295 296 // chaincodeInfoProviderImpl implements interface cceventmgmt.ChaincodeInfoProvider 297 type chaincodeInfoProviderImpl struct { 298 ledgerMgr *LedgerMgr 299 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider 300 } 301 302 // GetDeployedChaincodeInfo implements function in the interface cceventmgmt.ChaincodeInfoProvider 303 func (p *chaincodeInfoProviderImpl) GetDeployedChaincodeInfo(chainid string, 304 chaincodeDefinition *cceventmgmt.ChaincodeDefinition) (*ledger.DeployedChaincodeInfo, error) { 305 ledger, err := p.ledgerMgr.getOpenedLedger(chainid) 306 if err != nil { 307 return nil, err 308 } 309 qe, err := ledger.NewQueryExecutor() 310 if err != nil { 311 return nil, err 312 } 313 defer qe.Done() 314 deployedChaincodeInfo, err := p.deployedCCInfoProvider.ChaincodeInfo(chainid, chaincodeDefinition.Name, qe) 315 if err != nil || deployedChaincodeInfo == nil { 316 return nil, err 317 } 318 if deployedChaincodeInfo.Version != chaincodeDefinition.Version || 319 !bytes.Equal(deployedChaincodeInfo.Hash, chaincodeDefinition.Hash) { 320 // if the deployed chaincode with the given name has different version or different hash, return nil 321 return nil, nil 322 } 323 return deployedChaincodeInfo, nil 324 } 325 326 // RetrieveChaincodeArtifacts implements function in the interface cceventmgmt.ChaincodeInfoProvider 327 func (p *chaincodeInfoProviderImpl) RetrieveChaincodeArtifacts(chaincodeDefinition *cceventmgmt.ChaincodeDefinition) (installed bool, dbArtifactsTar []byte, err error) { 328 ccid := chaincodeDefinition.Name + ":" + chaincodeDefinition.Version 329 md, err := p.ledgerMgr.ebMetadataProvider.PackageMetadata(ccid) 330 if err != nil { 331 return false, nil, err 332 } 333 if md != nil { 334 return true, md, nil 335 } 336 return ccprovider.ExtractStatedbArtifactsForChaincode(ccid) 337 }