package alphabet import ( "context" "errors" "fmt" "sync" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/panjf2000/ants/v2" ) type ( // Indexer is a callback interface for inner ring global state. Indexer interface { AlphabetIndex(context.Context) int } // Contracts is an interface of the storage // of the alphabet contract addresses. Contracts interface { // GetByIndex must return the address of the // alphabet contract by index of the glagolitic // letter (e.g 0 for Az, 40 for Izhitsa). // // Must return false if the index does not // match any alphabet contract. GetByIndex(int) (util.Uint160, bool) } netmapClient interface { NetMap() (*netmap.NetMap, error) } morphClient interface { Invoke(ctx context.Context, contract util.Uint160, fee fixedn.Fixed8, method string, args ...any) (client.InvokeRes, error) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error BatchTransferGas(receivers []util.Uint160, amount fixedn.Fixed8) error } // Processor of events produced for alphabet contracts in the sidechain. Processor struct { parsedWallets []util.Uint160 // protects parsedWallets from concurrent change pwLock sync.RWMutex log *logger.Logger metrics metrics.Register pool *ants.Pool alphabetContracts Contracts netmapClient netmapClient morphClient morphClient irList Indexer storageEmission uint64 } // Params of the processor constructor. Params struct { ParsedWallets []util.Uint160 Log *logger.Logger Metrics metrics.Register PoolSize int AlphabetContracts Contracts NetmapClient netmapClient MorphClient morphClient IRList Indexer StorageEmission uint64 } ) // New creates a frostfs mainnet contract processor instance. func New(p *Params) (*Processor, error) { switch { case p.Log == nil: return nil, errors.New("ir/alphabet: logger is not set") case p.MorphClient == nil: return nil, errors.New("ir/alphabet: neo:morph client is not set") case p.IRList == nil: return nil, errors.New("ir/alphabet: global state is not set") } pool, err := ants.NewPool(p.PoolSize, ants.WithNonblocking(true)) if err != nil { return nil, fmt.Errorf("ir/frostfs: can't create worker pool: %w", err) } metricsRegister := p.Metrics if metricsRegister == nil { metricsRegister = metrics.DefaultRegister{} } return &Processor{ parsedWallets: p.ParsedWallets, log: p.Log, metrics: metricsRegister, pool: pool, alphabetContracts: p.AlphabetContracts, netmapClient: p.NetmapClient, morphClient: p.MorphClient, irList: p.IRList, storageEmission: p.StorageEmission, }, nil } func (ap *Processor) SetParsedWallets(parsedWallets []util.Uint160) { ap.pwLock.Lock() ap.parsedWallets = parsedWallets ap.pwLock.Unlock() } // ListenerNotificationHandlers for the 'event.Listener' event producer. func (ap *Processor) ListenerNotificationHandlers() []event.NotificationHandlerInfo { return nil } // ListenerNotaryParsers for the 'event.Listener' event producer. func (ap *Processor) ListenerNotaryParsers() []event.NotaryParserInfo { return nil } // ListenerNotaryHandlers for the 'event.Listener' event producer. func (ap *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo { return nil } // WaitPoolRunning waits while pool has running tasks // For use in test only. func (ap *Processor) WaitPoolRunning() { for ap.pool.Running() > 0 { time.Sleep(10 * time.Millisecond) } }