github.com/fnagchunpeng/fabric@v2.1.1+incompatible/core/deliverservice/deliveryclient.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package deliverservice 8 9 import ( 10 "context" 11 "crypto/x509" 12 "errors" 13 "fmt" 14 "sync" 15 "time" 16 17 "github.com/hyperledger/fabric-protos-go/orderer" 18 "github.com/hyperledger/fabric/common/flogging" 19 "github.com/hyperledger/fabric/common/util" 20 "github.com/hyperledger/fabric/internal/pkg/comm" 21 "github.com/hyperledger/fabric/internal/pkg/identity" 22 "github.com/hyperledger/fabric/internal/pkg/peer/blocksprovider" 23 "github.com/hyperledger/fabric/internal/pkg/peer/orderers" 24 "google.golang.org/grpc" 25 ) 26 27 var logger = flogging.MustGetLogger("deliveryClient") 28 29 // DeliverService used to communicate with orderers to obtain 30 // new blocks and send them to the committer service 31 type DeliverService interface { 32 // StartDeliverForChannel dynamically starts delivery of new blocks from ordering service 33 // to channel peers. 34 // When the delivery finishes, the finalizer func is called 35 StartDeliverForChannel(chainID string, ledgerInfo blocksprovider.LedgerInfo, finalizer func()) error 36 37 // StopDeliverForChannel dynamically stops delivery of new blocks from ordering service 38 // to channel peers. 39 StopDeliverForChannel(chainID string) error 40 41 // Stop terminates delivery service and closes the connection 42 Stop() 43 } 44 45 // deliverServiceImpl the implementation of the delivery service 46 // maintains connection to the ordering service and maps of 47 // blocks providers 48 type deliverServiceImpl struct { 49 conf *Config 50 blockProviders map[string]*blocksprovider.Deliverer 51 lock sync.RWMutex 52 stopping bool 53 } 54 55 // Config dictates the DeliveryService's properties, 56 // namely how it connects to an ordering service endpoint, 57 // how it verifies messages received from it, 58 // and how it disseminates the messages to other peers 59 type Config struct { 60 IsStaticLeader bool 61 // CryptoSvc performs cryptographic actions like message verification and signing 62 // and identity validation. 63 CryptoSvc blocksprovider.BlockVerifier 64 // Gossip enables to enumerate peers in the channel, send a message to peers, 65 // and add a block to the gossip state transfer layer. 66 Gossip blocksprovider.GossipServiceAdapter 67 // OrdererSource provides orderer endpoints, complete with TLS cert pools. 68 OrdererSource *orderers.ConnectionSource 69 // Signer is the identity used to sign requests. 70 Signer identity.SignerSerializer 71 // GRPC Client 72 DeliverGRPCClient *comm.GRPCClient 73 // Configuration values for deliver service. 74 // TODO: merge 2 Config struct 75 DeliverServiceConfig *DeliverServiceConfig 76 } 77 78 // NewDeliverService construction function to create and initialize 79 // delivery service instance. It tries to establish connection to 80 // the specified in the configuration ordering service, in case it 81 // fails to dial to it, return nil 82 func NewDeliverService(conf *Config) DeliverService { 83 ds := &deliverServiceImpl{ 84 conf: conf, 85 blockProviders: make(map[string]*blocksprovider.Deliverer), 86 } 87 return ds 88 } 89 90 type DialerAdapter struct { 91 Client *comm.GRPCClient 92 } 93 94 func (da DialerAdapter) Dial(address string, certPool *x509.CertPool) (*grpc.ClientConn, error) { 95 return da.Client.NewConnection(address, comm.CertPoolOverride(certPool)) 96 } 97 98 type DeliverAdapter struct{} 99 100 func (DeliverAdapter) Deliver(ctx context.Context, clientConn *grpc.ClientConn) (orderer.AtomicBroadcast_DeliverClient, error) { 101 return orderer.NewAtomicBroadcastClient(clientConn).Deliver(ctx) 102 } 103 104 // StartDeliverForChannel starts blocks delivery for channel 105 // initializes the grpc stream for given chainID, creates blocks provider instance 106 // that spawns in go routine to read new blocks starting from the position provided by ledger 107 // info instance. 108 func (d *deliverServiceImpl) StartDeliverForChannel(chainID string, ledgerInfo blocksprovider.LedgerInfo, finalizer func()) error { 109 d.lock.Lock() 110 defer d.lock.Unlock() 111 if d.stopping { 112 errMsg := fmt.Sprintf("Delivery service is stopping cannot join a new channel %s", chainID) 113 logger.Errorf(errMsg) 114 return errors.New(errMsg) 115 } 116 if _, exist := d.blockProviders[chainID]; exist { 117 errMsg := fmt.Sprintf("Delivery service - block provider already exists for %s found, can't start delivery", chainID) 118 logger.Errorf(errMsg) 119 return errors.New(errMsg) 120 } 121 logger.Info("This peer will retrieve blocks from ordering service and disseminate to other peers in the organization for channel", chainID) 122 123 dc := &blocksprovider.Deliverer{ 124 ChannelID: chainID, 125 Gossip: d.conf.Gossip, 126 Ledger: ledgerInfo, 127 BlockVerifier: d.conf.CryptoSvc, 128 Dialer: DialerAdapter{ 129 Client: d.conf.DeliverGRPCClient, 130 }, 131 Orderers: d.conf.OrdererSource, 132 DoneC: make(chan struct{}), 133 Signer: d.conf.Signer, 134 DeliverStreamer: DeliverAdapter{}, 135 Logger: flogging.MustGetLogger("peer.blocksprovider").With("channel", chainID), 136 MaxRetryDelay: d.conf.DeliverServiceConfig.ReConnectBackoffThreshold, 137 MaxRetryDuration: d.conf.DeliverServiceConfig.ReconnectTotalTimeThreshold, 138 InitialRetryDelay: 100 * time.Millisecond, 139 YieldLeadership: !d.conf.IsStaticLeader, 140 } 141 142 if d.conf.DeliverGRPCClient.MutualTLSRequired() { 143 dc.TLSCertHash = util.ComputeSHA256(d.conf.DeliverGRPCClient.Certificate().Certificate[0]) 144 } 145 146 d.blockProviders[chainID] = dc 147 go func() { 148 dc.DeliverBlocks() 149 finalizer() 150 }() 151 return nil 152 } 153 154 // StopDeliverForChannel stops blocks delivery for channel by stopping channel block provider 155 func (d *deliverServiceImpl) StopDeliverForChannel(chainID string) error { 156 d.lock.Lock() 157 defer d.lock.Unlock() 158 if d.stopping { 159 errMsg := fmt.Sprintf("Delivery service is stopping, cannot stop delivery for channel %s", chainID) 160 logger.Errorf(errMsg) 161 return errors.New(errMsg) 162 } 163 client, exist := d.blockProviders[chainID] 164 if !exist { 165 errMsg := fmt.Sprintf("Delivery service - no block provider for %s found, can't stop delivery", chainID) 166 logger.Errorf(errMsg) 167 return errors.New(errMsg) 168 } 169 client.Stop() 170 delete(d.blockProviders, chainID) 171 logger.Debug("This peer will stop pass blocks from orderer service to other peers") 172 return nil 173 } 174 175 // Stop all service and release resources 176 func (d *deliverServiceImpl) Stop() { 177 d.lock.Lock() 178 defer d.lock.Unlock() 179 // Marking flag to indicate the shutdown of the delivery service 180 d.stopping = true 181 182 for _, client := range d.blockProviders { 183 client.Stop() 184 } 185 }