package main import ( "context" "errors" "fmt" "time" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neofs-node/pkg/morph/client" "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper" "github.com/nspcc-dev/neofs-node/pkg/morph/event" netmapEvent "github.com/nspcc-dev/neofs-node/pkg/morph/event/netmap" "github.com/nspcc-dev/neofs-node/pkg/morph/subscriber" "github.com/nspcc-dev/neofs-node/pkg/util/rand" "go.uber.org/zap" ) const newEpochNotification = "NewEpoch" var ( errNoRPCEndpoints = errors.New("NEO RPC endpoints are not specified in config") errNoWSEndpoints = errors.New("websocket NEO listener endpoints are not specified in config") ) func initMorphComponents(c *cfg) { var err error fn := func(endpointCfg, dialTOCfg string, handler func(*client.Client), required bool) { addresses := c.viper.GetStringSlice(endpointCfg) if required && len(addresses) == 0 { fatalOnErr(errNoRPCEndpoints) } crand := rand.New() // math/rand with cryptographic source crand.Shuffle(len(addresses), func(i, j int) { addresses[i], addresses[j] = addresses[j], addresses[i] }) var dialTimeout time.Duration if dialTOCfg != "" { dialTimeout = c.viper.GetDuration(dialTOCfg) } for i := range addresses { cli, err := client.New(c.key, addresses[i], client.WithDialTimeout(dialTimeout)) if err == nil { c.log.Info("neo RPC connection established", zap.String("endpoint", addresses[i])) handler(cli) break } c.log.Info("failed to establish neo RPC connection, trying another", zap.String("endpoint", addresses[i]), zap.String("error", err.Error())) } fatalOnErr(err) } // replace to a separate initialing block during refactoring // since current function initializes sidechain components fn(cfgMainChainRPCAddress, cfgMainChainDialTimeout, func(cli *client.Client) { c.mainChainClient = cli }, false) fn(cfgMorphRPCAddress, "", func(cli *client.Client) { c.cfgMorph.client = cli }, true) wrap, err := wrapper.NewFromMorph(c.cfgMorph.client, c.cfgNetmap.scriptHash, 0) fatalOnErr(err) c.cfgObject.netMapStorage = newCachedNetmapStorage(c.cfgNetmap.state, wrap) c.cfgNetmap.wrapper = wrap } func listenMorphNotifications(c *cfg) { var ( err error subs subscriber.Subscriber ) endpoints := c.viper.GetStringSlice(cfgMorphNotifyRPCAddress) if len(endpoints) == 0 { fatalOnErr(errNoWSEndpoints) } timeout := c.viper.GetDuration(cfgMorphNotifyDialTimeout) crand := rand.New() // math/rand with cryptographic source crand.Shuffle(len(endpoints), func(i, j int) { endpoints[i], endpoints[j] = endpoints[j], endpoints[i] }) for i := range endpoints { subs, err = subscriber.New(c.ctx, &subscriber.Params{ Log: c.log, Endpoint: endpoints[i], DialTimeout: timeout, }) if err == nil { c.log.Info("websocket neo event listener established", zap.String("endpoint", endpoints[i])) break } c.log.Info("failed to establish websocket neo event listener, trying another", zap.String("endpoint", endpoints[i]), zap.String("error", err.Error())) } fatalOnErr(err) lis, err := event.NewListener(event.ListenerParams{ Logger: c.log, Subscriber: subs, }) fatalOnErr(err) c.workers = append(c.workers, newWorkerFromFunc(func(ctx context.Context) { lis.ListenWithError(ctx, c.internalErr) })) setNetmapNotificationParser(c, newEpochNotification, netmapEvent.ParseNewEpoch) registerNotificationHandlers(c.cfgNetmap.scriptHash, lis, c.cfgNetmap.parsers, c.cfgNetmap.subscribers) registerNotificationHandlers(c.cfgContainer.scriptHash, lis, c.cfgContainer.parsers, c.cfgContainer.subscribers) registerBlockHandler(lis, func(block *block.Block) { c.log.Debug("new block", zap.Uint32("index", block.Index)) tickBlockTimers(c) }) } func registerNotificationHandlers(scHash util.Uint160, lis event.Listener, parsers map[event.Type]event.Parser, subs map[event.Type][]event.Handler) { for typ, handlers := range subs { pi := event.ParserInfo{} pi.SetType(typ) pi.SetScriptHash(scHash) p, ok := parsers[typ] if !ok { panic(fmt.Sprintf("missing parser for event %s", typ)) } pi.SetParser(p) lis.SetParser(pi) for _, h := range handlers { hi := event.HandlerInfo{} hi.SetType(typ) hi.SetScriptHash(scHash) hi.SetHandler(h) lis.RegisterHandler(hi) } } } func registerBlockHandler(lis event.Listener, handler event.BlockHandler) { lis.RegisterBlockHandler(handler) }