Deliver Service
Both orderer and peer support Deliver service.
Deliver on Orderer
In AB gRPC server, _AtomicBroadcast_Deliver_Handler supports Deliver.
var _AtomicBroadcast_serviceDesc = grpc.ServiceDesc{
ServiceName: "orderer.AtomicBroadcast",
HandlerType: (*AtomicBroadcastServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "Broadcast",
Handler: _AtomicBroadcast_Broadcast_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "Deliver",
Handler: _AtomicBroadcast_Deliver_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "orderer/ab.proto",
}
Handler
Deliver Handler is initialized as:
dh: deliver.NewHandler(deliverSupport{Registrar: r}, timeWindow, mutualTLS, deliver.NewMetrics(metricsProvider), expirationCheckDisabled)
type deliverSupport struct {
*multichannel.Registrar
}
func (ds deliverSupport) GetChain(chainID string) deliver.Chain {
chain := ds.Registrar.GetChain(chainID)
if chain == nil {
return nil
}
return chain
}
// ChainManager provides a way for the Handler to look up the Chain.
type ChainManager interface {
GetChain(chainID string) Chain
}
deliverSupport implemets the ChainManager interface.
Below please check how the handler in invoked:
// Deliver sends a stream of blocks to a client after ordering
func (s *server) Deliver(srv ab.AtomicBroadcast_DeliverServer) error {
logger.Debugf("Starting new Deliver handler")
defer func() {
if r := recover(); r != nil {
logger.Criticalf("Deliver client triggered panic: %s\n%s", r, debug.Stack())
}
logger.Debugf("Closing Deliver stream")
}()
policyChecker := func(env *cb.Envelope, channelID string) error {
chain := s.GetChain(channelID)
if chain == nil {
return errors.Errorf("channel %s not found", channelID)
}
// In maintenance mode, we typically require the signature of /Channel/Orderer/Readers.
// This will block Deliver requests from peers (which normally satisfy /Channel/Readers).
sf := msgprocessor.NewSigFilter(policies.ChannelReaders, policies.ChannelOrdererReaders, chain)
return sf.Apply(env)
}
deliverServer := &deliver.Server{
PolicyChecker: deliver.PolicyCheckerFunc(policyChecker),
Receiver: &deliverMsgTracer{
Receiver: srv,
msgTracer: msgTracer{
debug: s.debug,
function: "Deliver",
},
},
ResponseSender: &responseSender{
AtomicBroadcast_DeliverServer: srv,
},
}
return s.dh.Handle(srv.Context(), deliverServer)
}
Peer
Peer will initialize the Deliver server, register with _Deliver_serviceDesc, 3 streams.
Handler
deliver.NewHandler(
&peer.DeliverChainManager{Peer: peerInstance},
coreConfig.AuthenticationTimeWindow,
mutualTLS,
metrics,
false,
)
...
abServer := &peer.DeliverServer{
DeliverHandler: deliver.NewHandler(
&peer.DeliverChainManager{Peer: peerInstance},
coreConfig.AuthenticationTimeWindow,
mutualTLS,
metrics,
false,
),
PolicyCheckerProvider: policyCheckerProvider,
}
pb.RegisterDeliverServer(peerServer.Server(), abServer)
...
var _Deliver_serviceDesc = grpc.ServiceDesc{
ServiceName: "protos.Deliver",
HandlerType: (*DeliverServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "Deliver",
Handler: _Deliver_Deliver_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "DeliverFiltered",
Handler: _Deliver_DeliverFiltered_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "DeliverWithPrivateData",
Handler: _Deliver_DeliverWithPrivateData_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "peer/events.proto",
}
Same Deliver Handler
Internally, Orderer and Peer are using the same unerlying Deliver Handler, which means they have the same capabilities.
Difference is Peer supports more Deliver services:
Deliver
This service sends entire blocks that have been committed to the ledger. If any events were set by a chaincode, these can be found within the ChaincodeActionPayload of the block.DeliverWithPrivateData
This service sends the same data as the Deliver service, and additionally includes any private data from collections that the client’s organization is authorized to access.DeliverFiltered
This service sends “filtered” blocks, minimal sets of information about blocks that have been committed to the ledger. It is intended to be used in a network where owners of the peers wish for external clients to primarily receive information about their transactions and the status of those transactions. If any events were set by a chaincode, these can be found within the FilteredChaincodeAction of the filtered block.
See DeliverServer interface in more details:
// DeliverServer is the server API for Deliver service.
type DeliverServer interface {
// Deliver first requires an Envelope of type ab.DELIVER_SEEK_INFO with
// Payload data as a marshaled orderer.SeekInfo message,
// then a stream of block replies is received
Deliver(Deliver_DeliverServer) error
// DeliverFiltered first requires an Envelope of type ab.DELIVER_SEEK_INFO with
// Payload data as a marshaled orderer.SeekInfo message,
// then a stream of **filtered** block replies is received
DeliverFiltered(Deliver_DeliverFilteredServer) error
// DeliverWithPrivateData first requires an Envelope of type ab.DELIVER_SEEK_INFO with
// Payload data as a marshaled orderer.SeekInfo message,
// then a stream of block and private data replies is received
DeliverWithPrivateData(Deliver_DeliverWithPrivateDataServer) error
}