package frostfs import ( "context" "errors" "fmt" "sync" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance" nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event" frostfsEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/frostfs" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" lru "github.com/hashicorp/golang-lru/v2" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/panjf2000/ants/v2" ) type ( // EpochState is a callback interface for inner ring global state. EpochState interface { EpochCounter() uint64 } // AlphabetState is a callback interface for inner ring global state. AlphabetState interface { IsAlphabet(context.Context) bool } // PrecisionConverter converts balance amount values. PrecisionConverter interface { ToBalancePrecision(int64) int64 } BalanceClient interface { Mint(ctx context.Context, p balance.MintPrm) error Lock(ctx context.Context, p balance.LockPrm) error Burn(ctx context.Context, p balance.BurnPrm) error } NetmapClient interface { SetConfig(ctx context.Context, p nmClient.SetConfigPrm) error } MorphClient interface { GasBalance() (res int64, err error) TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error } // Processor of events produced by frostfs contract in main net. Processor struct { log *logger.Logger metrics metrics.Register pool *ants.Pool frostfsContract util.Uint160 balanceClient BalanceClient netmapClient NetmapClient morphClient MorphClient epochState EpochState alphabetState AlphabetState converter PrecisionConverter mintEmitLock sync.Mutex mintEmitCache *lru.Cache[string, uint64] mintEmitThreshold uint64 mintEmitValue fixedn.Fixed8 gasBalanceThreshold int64 } // Params of the processor constructor. Params struct { Log *logger.Logger Metrics metrics.Register PoolSize int FrostFSContract util.Uint160 BalanceClient BalanceClient NetmapClient NetmapClient MorphClient MorphClient EpochState EpochState AlphabetState AlphabetState Converter PrecisionConverter MintEmitCacheSize int MintEmitThreshold uint64 // in epochs MintEmitValue fixedn.Fixed8 GasBalanceThreshold int64 } ) const ( depositNotification = "Deposit" withdrawNotification = "Withdraw" chequeNotification = "Cheque" configNotification = "SetConfig" ) // New creates frostfs mainnet contract processor instance. func New(p *Params) (*Processor, error) { switch { case p.Log == nil: return nil, errors.New("ir/frostfs: logger is not set") case p.MorphClient == nil: return nil, errors.New("ir/frostfs: neo:morph client is not set") case p.EpochState == nil: return nil, errors.New("ir/frostfs: global state is not set") case p.AlphabetState == nil: return nil, errors.New("ir/frostfs: global state is not set") case p.Converter == nil: return nil, errors.New("ir/frostfs: balance precision converter 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) } lruCache, err := lru.New[string, uint64](p.MintEmitCacheSize) if err != nil { return nil, fmt.Errorf("ir/frostfs: can't create LRU cache for gas emission: %w", err) } metricsRegister := p.Metrics if metricsRegister == nil { metricsRegister = metrics.DefaultRegister{} } return &Processor{ log: p.Log, metrics: metricsRegister, pool: pool, frostfsContract: p.FrostFSContract, balanceClient: p.BalanceClient, netmapClient: p.NetmapClient, morphClient: p.MorphClient, epochState: p.EpochState, alphabetState: p.AlphabetState, converter: p.Converter, mintEmitCache: lruCache, mintEmitThreshold: p.MintEmitThreshold, mintEmitValue: p.MintEmitValue, gasBalanceThreshold: p.GasBalanceThreshold, }, nil } // ListenerNotificationParsers for the 'event.Listener' event producer. func (np *Processor) ListenerNotificationParsers() []event.NotificationParserInfo { var ( parsers = make([]event.NotificationParserInfo, 0, 6) p event.NotificationParserInfo ) p.SetScriptHash(np.frostfsContract) // deposit event p.SetType(event.TypeFromString(depositNotification)) p.SetParser(frostfsEvent.ParseDeposit) parsers = append(parsers, p) // withdraw event p.SetType(event.TypeFromString(withdrawNotification)) p.SetParser(frostfsEvent.ParseWithdraw) parsers = append(parsers, p) // cheque event p.SetType(event.TypeFromString(chequeNotification)) p.SetParser(frostfsEvent.ParseCheque) parsers = append(parsers, p) // config event p.SetType(event.TypeFromString(configNotification)) p.SetParser(frostfsEvent.ParseConfig) parsers = append(parsers, p) return parsers } // ListenerNotificationHandlers for the 'event.Listener' event producer. func (np *Processor) ListenerNotificationHandlers() []event.NotificationHandlerInfo { var ( handlers = make([]event.NotificationHandlerInfo, 0, 6) h event.NotificationHandlerInfo ) h.SetScriptHash(np.frostfsContract) // deposit handler h.SetType(event.TypeFromString(depositNotification)) h.SetHandler(np.handleDeposit) handlers = append(handlers, h) // withdraw handler h.SetType(event.TypeFromString(withdrawNotification)) h.SetHandler(np.handleWithdraw) handlers = append(handlers, h) // cheque handler h.SetType(event.TypeFromString(chequeNotification)) h.SetHandler(np.handleCheque) handlers = append(handlers, h) // config handler h.SetType(event.TypeFromString(configNotification)) h.SetHandler(np.handleConfig) handlers = append(handlers, h) return handlers } // ListenerNotaryParsers for the 'event.Listener' event producer. func (np *Processor) ListenerNotaryParsers() []event.NotaryParserInfo { return nil } // ListenerNotaryHandlers for the 'event.Listener' event producer. func (np *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo { return nil }