orderer
The initialization procedure is simliar with peer’s.
- Load configuration
- Initialize loggging system
- Start operation system, http listening…
- Create gRPC server
- CreateLedgerFactory
- Bootstrap if method is ‘file’
– Extract Genesis block and validate
– Extract system channel
– Handle Cluster setting…
– initializeBootstrapChannel if ledger is empty - initializeMultichannelRegistrar
– Make consenters: [solo,kafka,raft]
– Make a multi-channel registar
– Start the chain worker for each existing channel (chain worker refers to the consensus of the chain) - Hook OS signals
- Start cluster server if cluster enabled-
- Make AtomicBroadcastServer, register to grpc, with Broadcast & Deliver handlers
- Start the underlying grpc.Server
// Main is the entry point of orderer process
func Main() {
// Load coniguration, orderer.yaml
conf, err := localconfig.Load()
if err != nil {
logger.Error("failed to parse config: ", err)
os.Exit(1)
}
// logging ... FABRIC_LOGGING_SPEC & FABRIC_LOGGING_FORMAT
initializeLogging()
// printing configurations on console
prettyPrintStruct(conf)
cryptoProvider := factory.GetDefault()
// Get MSP signer
signer, signErr := loadLocalMSP(conf).GetDefaultSigningIdentity()
if signErr != nil {
logger.Panicf("Failed to get local MSP identity: %s", signErr)
}
// start operation system, http server...
opsSystem := newOperationsSystem(conf.Operations, conf.Metrics)
if err = opsSystem.Start(); err != nil {
logger.Panicf("failed to initialize operations subsystem: %s", err)
}
defer opsSystem.Stop()
metricsProvider := opsSystem.Provider
logObserver := floggingmetrics.NewObserver(metricsProvider)
flogging.SetObserver(logObserver)
serverConfig := initializeServerConfig(conf, metricsProvider)
grpcServer := initializeGrpcServer(conf, serverConfig)
...
if conf.General.Profile.Enabled {
go initializeProfilingService(conf)
}
ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)
logger.Info("Beginning to serve requests")
grpcServer.Start()
}
order data structure
// Registrar serves as a point of access and control for the individual channel resources.
type Registrar struct {
config localconfig.TopLevel
lock sync.RWMutex
chains map[string]*ChainSupport
consenters map[string]consensus.Consenter
ledgerFactory blockledger.Factory
signer identity.SignerSerializer
blockcutterMetrics *blockcutter.Metrics
systemChannelID string
systemChannel *ChainSupport
templator msgprocessor.ChannelConfigTemplator
callbacks []channelconfig.BundleActor
bccsp bccsp.BCCSP
}
Besides, ChainGetter and ChainCreator Interfaces are implemented by Registrar.
Broadcast & Deliver handlers
Broadcast : fabric\orderer\common\broadcast\broadcast.go
Deliver : fabric\common\deliver\deliver.go
// NewServer creates an ab.AtomicBroadcastServer based on the broadcast target and ledger Reader
func NewServer(
r *multichannel.Registrar,
metricsProvider metrics.Provider,
debug *localconfig.Debug,
timeWindow time.Duration,
mutualTLS bool,
expirationCheckDisabled bool,
) ab.AtomicBroadcastServer {
s := &server{
dh: deliver.NewHandler(deliverSupport{Registrar: r}, timeWindow, mutualTLS, deliver.NewMetrics(metricsProvider), expirationCheckDisabled),
bh: &broadcast.Handler{
SupportRegistrar: broadcastSupport{Registrar: r},
Metrics: broadcast.NewMetrics(metricsProvider),
},
debug: debug,
Registrar: r,
}
return s
}
// Broadcast receives a stream of messages from a client for ordering
func (s *server) Broadcast(srv ab.AtomicBroadcast_BroadcastServer) error {
logger.Debugf("Starting new Broadcast handler")
defer func() {
if r := recover(); r != nil {
logger.Criticalf("Broadcast client triggered panic: %s\n%s", r, debug.Stack())
}
logger.Debugf("Closing Broadcast stream")
}()
return s.bh.Handle(&broadcastMsgTracer{
AtomicBroadcast_BroadcastServer: srv,
msgTracer: msgTracer{
debug: s.debug,
function: "Broadcast",
},
})
}
// 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)
}
broadcase handler
It uses gRPC Stream to handle multiple messages.
// Handle reads requests from a Broadcast stream, processes them, and returns the responses to the stream
func (bh *Handler) Handle(srv ab.AtomicBroadcast_BroadcastServer) error {
addr := util.ExtractRemoteAddress(srv.Context())
for {
msg, err := srv.Recv()
if err == io.EOF {
logger.Debugf("Received EOF from %s, hangup", addr)
return nil
}
if err != nil {
logger.Warningf("Error reading from %s: %s", addr, err)
return err
}
resp := bh.ProcessMessage(msg, addr)
err = srv.Send(resp)
if resp.Status != cb.Status_SUCCESS {
return err
}
if err != nil {
logger.Warningf("Error sending to %s: %s", addr, err)
return err
}
}
}
In bh.ProcessMessage(msg, addr) :
- Message will be firstly processed by multichannel Registar.BroadcastChannelSupport(), to get the message header and the Channel Processor.
- Messgae will then be processed as by processor.ProcessConfigUpdateMsg(msg) if it is a config msg or, by processor.ProcessNotmalMsg(msg) if it is not
func (r *Registrar) BroadcastChannelSupport(msg *cb.Envelope) (*cb.ChannelHeader, bool, *ChainSupport, error) {
chdr, err := protoutil.ChannelHeader(msg)
if err != nil {
return nil, false, nil, fmt.Errorf("could not determine channel ID: %s", err)
}
cs := r.GetChain(chdr.ChannelId)
// New channel creation
if cs == nil {
if r.systemChannel == nil {
return nil, false, nil, errors.New("channel creation request not allowed because the orderer system channel is not yet defined")
}
cs = r.systemChannel
}
isConfig := false
switch cs.ClassifyMsg(chdr) {
case msgprocessor.ConfigUpdateMsg:
isConfig = true
case msgprocessor.ConfigMsg:
return chdr, false, nil, errors.New("message is of type that cannot be processed directly")
default:
}
return chdr, isConfig, cs, nil
}
deliver handler
Delivers blocks to peers as requested. In stream gRPC, deliverBlocks() will be invoked fpr every received message/enelope.
// Handle receives incoming deliver requests.
func (h *Handler) Handle(ctx context.Context, srv *Server) error {
for {
logger.Debugf("Attempting to read seek info message from %s", addr)
envelope, err := srv.Recv()
if err == io.EOF {
logger.Debugf("Received EOF from %s, hangup", addr)
return nil
}
status, err := h.deliverBlocks(ctx, srv, envelope)
...
err = srv.SendStatusResponse(status)
...
}
}
deliverBlocks:
- Parse message/envelope, to get the payload/chanHeader/SigHeader
- Get the channel by chanHeader.ChannelId
- unmarshal payload to get the SeekInfo, which specifies the range of requested blocks to return
- accessControl for permission check
- SendBlockResponse, multiple times