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