github.com/defanghe/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  }