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  }