github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+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/core/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 // CryptoSvc performs cryptographic actions like message verification and signing 61 // and identity validation. 62 CryptoSvc blocksprovider.BlockVerifier 63 // Gossip enables to enumerate peers in the channel, send a message to peers, 64 // and add a block to the gossip state transfer layer. 65 Gossip blocksprovider.GossipServiceAdapter 66 // OrdererSource provides orderer endpoints, complete with TLS cert pools. 67 OrdererSource *orderers.ConnectionSource 68 // Signer is the identity used to sign requests. 69 Signer identity.SignerSerializer 70 // GRPC Client 71 DeliverGRPCClient *comm.GRPCClient 72 // Configuration values for deliver service. 73 // TODO: merge 2 Config struct 74 DeliverServiceConfig *DeliverServiceConfig 75 } 76 77 // NewDeliverService construction function to create and initialize 78 // delivery service instance. It tries to establish connection to 79 // the specified in the configuration ordering service, in case it 80 // fails to dial to it, return nil 81 func NewDeliverService(conf *Config) DeliverService { 82 ds := &deliverServiceImpl{ 83 conf: conf, 84 blockProviders: make(map[string]*blocksprovider.Deliverer), 85 } 86 return ds 87 } 88 89 type DialerAdapter struct { 90 Client *comm.GRPCClient 91 } 92 93 func (da DialerAdapter) Dial(address string, certPool *x509.CertPool) (*grpc.ClientConn, error) { 94 return da.Client.NewConnection(address, comm.CertPoolOverride(certPool)) 95 } 96 97 type DeliverAdapter struct{} 98 99 func (DeliverAdapter) Deliver(ctx context.Context, clientConn *grpc.ClientConn) (orderer.AtomicBroadcast_DeliverClient, error) { 100 return orderer.NewAtomicBroadcastClient(clientConn).Deliver(ctx) 101 } 102 103 // StartDeliverForChannel starts blocks delivery for channel 104 // initializes the grpc stream for given chainID, creates blocks provider instance 105 // that spawns in go routine to read new blocks starting from the position provided by ledger 106 // info instance. 107 func (d *deliverServiceImpl) StartDeliverForChannel(chainID string, ledgerInfo blocksprovider.LedgerInfo, finalizer func()) error { 108 d.lock.Lock() 109 defer d.lock.Unlock() 110 if d.stopping { 111 errMsg := fmt.Sprintf("Delivery service is stopping cannot join a new channel %s", chainID) 112 logger.Errorf(errMsg) 113 return errors.New(errMsg) 114 } 115 if _, exist := d.blockProviders[chainID]; exist { 116 errMsg := fmt.Sprintf("Delivery service - block provider already exists for %s found, can't start delivery", chainID) 117 logger.Errorf(errMsg) 118 return errors.New(errMsg) 119 } 120 logger.Info("This peer will retrieve blocks from ordering service and disseminate to other peers in the organization for channel", chainID) 121 dc := &blocksprovider.Deliverer{ 122 ChannelID: chainID, 123 Gossip: d.conf.Gossip, 124 Ledger: ledgerInfo, 125 BlockVerifier: d.conf.CryptoSvc, 126 Dialer: DialerAdapter{ 127 Client: d.conf.DeliverGRPCClient, 128 }, 129 Orderers: d.conf.OrdererSource, 130 DoneC: make(chan struct{}), 131 Signer: d.conf.Signer, 132 DeliverStreamer: DeliverAdapter{}, 133 Logger: flogging.MustGetLogger("peer.blocksprovider").With("channel", chainID), 134 MaxRetryDelay: time.Duration(d.conf.DeliverServiceConfig.ReConnectBackoffThreshold), 135 MaxRetryDuration: d.conf.DeliverServiceConfig.ReconnectTotalTimeThreshold, 136 InitialRetryDelay: 100 * time.Millisecond, 137 } 138 139 if d.conf.DeliverGRPCClient.MutualTLSRequired() { 140 dc.TLSCertHash = util.ComputeSHA256(d.conf.DeliverGRPCClient.Certificate().Certificate[0]) 141 } 142 143 d.blockProviders[chainID] = dc 144 go func() { 145 dc.DeliverBlocks() 146 finalizer() 147 }() 148 return nil 149 } 150 151 // StopDeliverForChannel stops blocks delivery for channel by stopping channel block provider 152 func (d *deliverServiceImpl) StopDeliverForChannel(chainID string) error { 153 d.lock.Lock() 154 defer d.lock.Unlock() 155 if d.stopping { 156 errMsg := fmt.Sprintf("Delivery service is stopping, cannot stop delivery for channel %s", chainID) 157 logger.Errorf(errMsg) 158 return errors.New(errMsg) 159 } 160 client, exist := d.blockProviders[chainID] 161 if !exist { 162 errMsg := fmt.Sprintf("Delivery service - no block provider for %s found, can't stop delivery", chainID) 163 logger.Errorf(errMsg) 164 return errors.New(errMsg) 165 } 166 client.Stop() 167 delete(d.blockProviders, chainID) 168 logger.Debug("This peer will stop pass blocks from orderer service to other peers") 169 return nil 170 } 171 172 // Stop all service and release resources 173 func (d *deliverServiceImpl) Stop() { 174 d.lock.Lock() 175 defer d.lock.Unlock() 176 // Marking flag to indicate the shutdown of the delivery service 177 d.stopping = true 178 179 for _, client := range d.blockProviders { 180 client.Stop() 181 } 182 }