github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/ledgermgmt/ledger_mgmt.go (about) 1 /* 2 Copyright IBM Corp. 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/hyperledger/fabric-protos-go/common" 15 "github.com/hyperledger/fabric/common/flogging" 16 "github.com/hyperledger/fabric/common/metrics" 17 "github.com/hyperledger/fabric/core/common/ccprovider" 18 "github.com/hyperledger/fabric/core/ledger" 19 "github.com/hyperledger/fabric/core/ledger/cceventmgmt" 20 "github.com/hyperledger/fabric/core/ledger/kvledger" 21 "github.com/pkg/errors" 22 ) 23 24 var logger = flogging.MustGetLogger("ledgermgmt") 25 26 // ErrLedgerAlreadyOpened is thrown by a CreateLedger call if a ledger with the given id is already opened 27 var ErrLedgerAlreadyOpened = errors.New("ledger already opened") 28 29 // ErrLedgerMgmtNotInitialized is thrown when ledger mgmt is used before initializing this 30 var ErrLedgerMgmtNotInitialized = errors.New("ledger mgmt should be initialized before using") 31 32 // LedgerMgr manages ledgers for all channels 33 type LedgerMgr struct { 34 lock sync.Mutex 35 openedLedgers map[string]ledger.PeerLedger 36 ledgerProvider ledger.PeerLedgerProvider 37 ebMetadataProvider MetadataProvider 38 } 39 40 type MetadataProvider interface { 41 PackageMetadata(ccid string) ([]byte, error) 42 } 43 44 // Initializer encapsulates all the external dependencies for the ledger module 45 type Initializer struct { 46 CustomTxProcessors map[common.HeaderType]ledger.CustomTxProcessor 47 StateListeners []ledger.StateListener 48 DeployedChaincodeInfoProvider ledger.DeployedChaincodeInfoProvider 49 MembershipInfoProvider ledger.MembershipInfoProvider 50 ChaincodeLifecycleEventProvider ledger.ChaincodeLifecycleEventProvider 51 MetricsProvider metrics.Provider 52 HealthCheckRegistry ledger.HealthCheckRegistry 53 Config *ledger.Config 54 Hasher ledger.Hasher 55 EbMetadataProvider MetadataProvider 56 } 57 58 // NewLedgerMgr creates a new LedgerMgr 59 func NewLedgerMgr(initializer *Initializer) *LedgerMgr { 60 logger.Info("Initializing LedgerMgr") 61 finalStateListeners := addListenerForCCEventsHandler( 62 initializer.DeployedChaincodeInfoProvider, 63 initializer.StateListeners, 64 ) 65 provider, err := kvledger.NewProvider( 66 &ledger.Initializer{ 67 StateListeners: finalStateListeners, 68 DeployedChaincodeInfoProvider: initializer.DeployedChaincodeInfoProvider, 69 MembershipInfoProvider: initializer.MembershipInfoProvider, 70 ChaincodeLifecycleEventProvider: initializer.ChaincodeLifecycleEventProvider, 71 MetricsProvider: initializer.MetricsProvider, 72 HealthCheckRegistry: initializer.HealthCheckRegistry, 73 Config: initializer.Config, 74 CustomTxProcessors: initializer.CustomTxProcessors, 75 Hasher: initializer.Hasher, 76 }, 77 ) 78 if err != nil { 79 panic(fmt.Sprintf("Error in instantiating ledger provider: %s", err)) 80 } 81 ledgerMgr := &LedgerMgr{ 82 openedLedgers: make(map[string]ledger.PeerLedger), 83 ledgerProvider: provider, 84 ebMetadataProvider: initializer.EbMetadataProvider, 85 } 86 // TODO remove the following package level init 87 cceventmgmt.Initialize(&chaincodeInfoProviderImpl{ 88 ledgerMgr, 89 initializer.DeployedChaincodeInfoProvider, 90 }) 91 logger.Info("Initialized LedgerMgr") 92 return ledgerMgr 93 } 94 95 // CreateLedger creates a new ledger with the given genesis block. 96 // This function guarantees that the creation of ledger and committing the genesis block would an atomic action 97 // The chain id retrieved from the genesis block is treated as a ledger id 98 func (m *LedgerMgr) CreateLedger(id string, genesisBlock *common.Block) (ledger.PeerLedger, error) { 99 m.lock.Lock() 100 defer m.lock.Unlock() 101 logger.Infof("Creating ledger [%s] with genesis block", id) 102 l, err := m.ledgerProvider.Create(genesisBlock) 103 if err != nil { 104 return nil, err 105 } 106 m.openedLedgers[id] = l 107 logger.Infof("Created ledger [%s] with genesis block", id) 108 return &closableLedger{ 109 ledgerMgr: m, 110 id: id, 111 PeerLedger: l, 112 }, nil 113 } 114 115 // OpenLedger returns a ledger for the given id 116 func (m *LedgerMgr) OpenLedger(id string) (ledger.PeerLedger, error) { 117 logger.Infof("Opening ledger with id = %s", id) 118 m.lock.Lock() 119 defer m.lock.Unlock() 120 _, ok := m.openedLedgers[id] 121 if ok { 122 return nil, ErrLedgerAlreadyOpened 123 } 124 l, err := m.ledgerProvider.Open(id) 125 if err != nil { 126 return nil, err 127 } 128 m.openedLedgers[id] = l 129 logger.Infof("Opened ledger with id = %s", id) 130 return &closableLedger{ 131 ledgerMgr: m, 132 id: id, 133 PeerLedger: l, 134 }, nil 135 } 136 137 // GetLedgerIDs returns the ids of the ledgers created 138 func (m *LedgerMgr) GetLedgerIDs() ([]string, error) { 139 m.lock.Lock() 140 defer m.lock.Unlock() 141 return m.ledgerProvider.List() 142 } 143 144 // Close closes all the opened ledgers and any resources held for ledger management 145 func (m *LedgerMgr) Close() { 146 logger.Infof("Closing ledger mgmt") 147 m.lock.Lock() 148 defer m.lock.Unlock() 149 for _, l := range m.openedLedgers { 150 l.Close() 151 } 152 m.ledgerProvider.Close() 153 m.openedLedgers = nil 154 logger.Infof("ledger mgmt closed") 155 } 156 157 func (m *LedgerMgr) getOpenedLedger(ledgerID string) (ledger.PeerLedger, error) { 158 m.lock.Lock() 159 defer m.lock.Unlock() 160 l, ok := m.openedLedgers[ledgerID] 161 if !ok { 162 return nil, errors.Errorf("Ledger not opened [%s]", ledgerID) 163 } 164 return l, nil 165 } 166 167 func (m *LedgerMgr) closeLedger(ledgerID string) { 168 m.lock.Lock() 169 defer m.lock.Unlock() 170 l, ok := m.openedLedgers[ledgerID] 171 if ok { 172 l.Close() 173 delete(m.openedLedgers, ledgerID) 174 } 175 } 176 177 // closableLedger extends from actual validated ledger and overwrites the Close method 178 type closableLedger struct { 179 ledgerMgr *LedgerMgr 180 id string 181 ledger.PeerLedger 182 } 183 184 // Close closes the actual ledger and removes the entries from opened ledgers map 185 func (l *closableLedger) Close() { 186 l.ledgerMgr.closeLedger(l.id) 187 } 188 189 // lscc namespace listener for chaincode instantiate transactions (which manipulates data in 'lscc' namespace) 190 // this code should be later moved to peer and passed via `Initialize` function of ledgermgmt 191 func addListenerForCCEventsHandler( 192 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider, 193 stateListeners []ledger.StateListener) []ledger.StateListener { 194 return append(stateListeners, &cceventmgmt.KVLedgerLSCCStateListener{DeployedChaincodeInfoProvider: deployedCCInfoProvider}) 195 } 196 197 // chaincodeInfoProviderImpl implements interface cceventmgmt.ChaincodeInfoProvider 198 type chaincodeInfoProviderImpl struct { 199 ledgerMgr *LedgerMgr 200 deployedCCInfoProvider ledger.DeployedChaincodeInfoProvider 201 } 202 203 // GetDeployedChaincodeInfo implements function in the interface cceventmgmt.ChaincodeInfoProvider 204 func (p *chaincodeInfoProviderImpl) GetDeployedChaincodeInfo(chainid string, 205 chaincodeDefinition *cceventmgmt.ChaincodeDefinition) (*ledger.DeployedChaincodeInfo, error) { 206 ledger, err := p.ledgerMgr.getOpenedLedger(chainid) 207 if err != nil { 208 return nil, err 209 } 210 qe, err := ledger.NewQueryExecutor() 211 if err != nil { 212 return nil, err 213 } 214 defer qe.Done() 215 deployedChaincodeInfo, err := p.deployedCCInfoProvider.ChaincodeInfo(chainid, chaincodeDefinition.Name, qe) 216 if err != nil || deployedChaincodeInfo == nil { 217 return nil, err 218 } 219 if deployedChaincodeInfo.Version != chaincodeDefinition.Version || 220 !bytes.Equal(deployedChaincodeInfo.Hash, chaincodeDefinition.Hash) { 221 // if the deployed chaincode with the given name has different version or different hash, return nil 222 return nil, nil 223 } 224 return deployedChaincodeInfo, nil 225 } 226 227 // RetrieveChaincodeArtifacts implements function in the interface cceventmgmt.ChaincodeInfoProvider 228 func (p *chaincodeInfoProviderImpl) RetrieveChaincodeArtifacts(chaincodeDefinition *cceventmgmt.ChaincodeDefinition) (installed bool, dbArtifactsTar []byte, err error) { 229 ccid := chaincodeDefinition.Name + ":" + chaincodeDefinition.Version 230 md, err := p.ledgerMgr.ebMetadataProvider.PackageMetadata(ccid) 231 if err != nil { 232 return false, nil, err 233 } 234 if md != nil { 235 return true, md, nil 236 } 237 return ccprovider.ExtractStatedbArtifactsForChaincode(ccid) 238 }