github.com/hyperledger-labs/bdls@v2.1.1+incompatible/core/chaincode/handler_registry.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package chaincode
     8  
     9  import (
    10  	"sync"
    11  
    12  	"github.com/hyperledger/fabric/core/ledger"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // HandlerRegistry maintains chaincode Handler instances.
    17  type HandlerRegistry struct {
    18  	allowUnsolicitedRegistration bool // from cs.userRunsCC
    19  
    20  	mutex     sync.Mutex              // lock covering handlers and launching
    21  	handlers  map[string]*Handler     // chaincode cname to associated handler
    22  	launching map[string]*LaunchState // launching chaincodes to LaunchState
    23  }
    24  
    25  type LaunchState struct {
    26  	mutex    sync.Mutex
    27  	notified bool
    28  	done     chan struct{}
    29  	err      error
    30  }
    31  
    32  func NewLaunchState() *LaunchState {
    33  	return &LaunchState{
    34  		done: make(chan struct{}),
    35  	}
    36  }
    37  
    38  func (l *LaunchState) Done() <-chan struct{} {
    39  	return l.done
    40  }
    41  
    42  func (l *LaunchState) Err() error {
    43  	l.mutex.Lock()
    44  	err := l.err
    45  	l.mutex.Unlock()
    46  	return err
    47  }
    48  
    49  func (l *LaunchState) Notify(err error) {
    50  	l.mutex.Lock()
    51  	if !l.notified {
    52  		l.notified = true
    53  		l.err = err
    54  		close(l.done)
    55  	}
    56  	l.mutex.Unlock()
    57  }
    58  
    59  // NewHandlerRegistry constructs a HandlerRegistry.
    60  func NewHandlerRegistry(allowUnsolicitedRegistration bool) *HandlerRegistry {
    61  	return &HandlerRegistry{
    62  		handlers:                     map[string]*Handler{},
    63  		launching:                    map[string]*LaunchState{},
    64  		allowUnsolicitedRegistration: allowUnsolicitedRegistration,
    65  	}
    66  }
    67  
    68  // Launching indicates that chaincode is being launched. The LaunchState that
    69  // is returned provides mechanisms to determine when the operation has
    70  // completed and whether or not it failed. The bool indicates whether or not
    71  // the chaincode has already been started.
    72  func (r *HandlerRegistry) Launching(ccid string) (*LaunchState, bool) {
    73  	r.mutex.Lock()
    74  	defer r.mutex.Unlock()
    75  
    76  	// launch happened or already happening
    77  	if launchState, ok := r.launching[ccid]; ok {
    78  		return launchState, true
    79  	}
    80  
    81  	// handler registered without going through launch
    82  	if _, ok := r.handlers[ccid]; ok {
    83  		launchState := NewLaunchState()
    84  		launchState.Notify(nil)
    85  		return launchState, true
    86  	}
    87  
    88  	// first attempt to launch so the runtime needs to start
    89  	launchState := NewLaunchState()
    90  	r.launching[ccid] = launchState
    91  	return launchState, false
    92  }
    93  
    94  // Ready indicates that the chaincode registration has completed and the
    95  // READY response has been sent to the chaincode.
    96  func (r *HandlerRegistry) Ready(ccid string) {
    97  	r.mutex.Lock()
    98  	defer r.mutex.Unlock()
    99  
   100  	launchStatus := r.launching[ccid]
   101  	if launchStatus != nil {
   102  		launchStatus.Notify(nil)
   103  	}
   104  }
   105  
   106  // Failed indicates that registration of a launched chaincode has failed.
   107  func (r *HandlerRegistry) Failed(ccid string, err error) {
   108  	r.mutex.Lock()
   109  	defer r.mutex.Unlock()
   110  
   111  	launchStatus := r.launching[ccid]
   112  	if launchStatus != nil {
   113  		launchStatus.Notify(err)
   114  	}
   115  }
   116  
   117  // Handler retrieves the handler for a chaincode instance.
   118  func (r *HandlerRegistry) Handler(ccid string) *Handler {
   119  	r.mutex.Lock()
   120  	h := r.handlers[ccid]
   121  	r.mutex.Unlock()
   122  	return h
   123  }
   124  
   125  // Register adds a chaincode handler to the registry.
   126  // An error will be returned if a handler is already registered for the
   127  // chaincode. An error will also be returned if the chaincode has not already
   128  // been "launched", and unsolicited registration is not allowed.
   129  func (r *HandlerRegistry) Register(h *Handler) error {
   130  	r.mutex.Lock()
   131  	defer r.mutex.Unlock()
   132  
   133  	if r.handlers[h.chaincodeID] != nil {
   134  		chaincodeLogger.Debugf("duplicate registered handler(key:%s) return error", h.chaincodeID)
   135  		return errors.Errorf("duplicate chaincodeID: %s", h.chaincodeID)
   136  	}
   137  
   138  	// This chaincode was not launched by the peer but is attempting
   139  	// to register. Only allowed in development mode.
   140  	if r.launching[h.chaincodeID] == nil && !r.allowUnsolicitedRegistration {
   141  		return errors.Errorf("peer will not accept external chaincode connection %s (except in dev mode)", h.chaincodeID)
   142  	}
   143  
   144  	r.handlers[h.chaincodeID] = h
   145  
   146  	chaincodeLogger.Debugf("registered handler complete for chaincode %s", h.chaincodeID)
   147  	return nil
   148  }
   149  
   150  // Deregister clears references to state associated specified chaincode.
   151  // As part of the cleanup, it closes the handler so it can cleanup any state.
   152  // If the registry does not contain the provided handler, an error is returned.
   153  func (r *HandlerRegistry) Deregister(ccid string) error {
   154  	chaincodeLogger.Debugf("deregister handler: %s", ccid)
   155  
   156  	r.mutex.Lock()
   157  	handler := r.handlers[ccid]
   158  	delete(r.handlers, ccid)
   159  	delete(r.launching, ccid)
   160  	r.mutex.Unlock()
   161  
   162  	if handler == nil {
   163  		return errors.Errorf("could not find handler: %s", ccid)
   164  	}
   165  
   166  	handler.Close()
   167  
   168  	chaincodeLogger.Debugf("deregistered handler with key: %s", ccid)
   169  	return nil
   170  }
   171  
   172  type TxQueryExecutorGetter struct {
   173  	HandlerRegistry *HandlerRegistry
   174  	CCID            string
   175  }
   176  
   177  func (g *TxQueryExecutorGetter) TxQueryExecutor(chainID, txID string) ledger.SimpleQueryExecutor {
   178  	handler := g.HandlerRegistry.Handler(g.CCID)
   179  	if handler == nil {
   180  		return nil
   181  	}
   182  	txContext := handler.TXContexts.Get(chainID, txID)
   183  	if txContext == nil {
   184  		return nil
   185  	}
   186  	return txContext.TXSimulator
   187  }