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
}