github.com/binyushen/fabric@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 }