package governance import ( "context" "errors" "fmt" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" frostfscontract "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs" nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/rolemanagement" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" "github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/panjf2000/ants/v2" ) // ProcessorPoolSize limits the pool size for governance Processor. Processor manages // governance sync tasks. This process must not be interrupted by other sync // operation, so we limit the pool size for the processor to one. const ProcessorPoolSize = 1 type ( // AlphabetState is a callback interface for innerring global state. AlphabetState interface { IsAlphabet(context.Context) bool } ) // VoteValidatorPrm groups parameters of the VoteForSidechainValidator // operation. type VoteValidatorPrm struct { Validators keys.PublicKeys Hash *util.Uint256 // hash of the transaction that triggered voting } // Voter is a callback interface for alphabet contract voting. type Voter interface { VoteForSidechainValidator(context.Context, VoteValidatorPrm) error } type ( // EpochState is a callback interface for innerring global state. EpochState interface { EpochCounter() uint64 } // IRFetcher is a callback interface for innerring keys. // Implementation must take into account availability of // the notary contract. IRFetcher interface { InnerRingKeys() (keys.PublicKeys, error) } FrostFSClient interface { AlphabetUpdate(ctx context.Context, p frostfscontract.AlphabetUpdatePrm) error } NetmapClient interface { UpdateInnerRing(p nmClient.UpdateIRPrm) error } MainnetClient interface { NeoFSAlphabetList() (res keys.PublicKeys, err error) GetDesignateHash() util.Uint160 } MorphClient interface { Committee() (res keys.PublicKeys, err error) UpdateNeoFSAlphabetList(ctx context.Context, prm client.UpdateAlphabetListPrm) error UpdateNotaryList(ctx context.Context, prm client.UpdateNotaryListPrm) error } // Processor of events related to governance in the network. Processor struct { log *logger.Logger metrics metrics.Register pool *ants.Pool frostfsClient FrostFSClient alphabetState AlphabetState epochState EpochState voter Voter irFetcher IRFetcher mainnetClient MainnetClient morphClient MorphClient designate util.Uint160 } // Params of the processor constructor. Params struct { Log *logger.Logger Metrics metrics.Register AlphabetState AlphabetState EpochState EpochState Voter Voter IRFetcher IRFetcher MorphClient MorphClient MainnetClient MainnetClient FrostFSClient FrostFSClient } ) // New creates a balance contract processor instance. func New(p *Params) (*Processor, error) { switch { case p.Log == nil: return nil, errors.New("ir/governance: logger is not set") case p.MainnetClient == nil: return nil, errors.New("ir/governance: neo:mainnet client is not set") case p.MorphClient == nil: return nil, errors.New("ir/governance: neo:sidechain client is not set") case p.AlphabetState == nil: return nil, errors.New("ir/governance: global state is not set") case p.EpochState == nil: return nil, errors.New("ir/governance: global state is not set") case p.Voter == nil: return nil, errors.New("ir/governance: global state is not set") case p.IRFetcher == nil: return nil, errors.New("ir/governance: innerring keys fetcher is not set") } pool, err := ants.NewPool(ProcessorPoolSize, ants.WithNonblocking(true)) if err != nil { return nil, fmt.Errorf("ir/governance: can't create worker pool: %w", err) } metricsRegister := p.Metrics if metricsRegister == nil { metricsRegister = metrics.DefaultRegister{} } // result is cached by neo-go, so we can pre-calc it designate := p.MainnetClient.GetDesignateHash() return &Processor{ log: p.Log, metrics: metricsRegister, pool: pool, frostfsClient: p.FrostFSClient, alphabetState: p.AlphabetState, epochState: p.EpochState, voter: p.Voter, irFetcher: p.IRFetcher, mainnetClient: p.MainnetClient, morphClient: p.MorphClient, designate: designate, }, nil } // ListenerNotificationParsers for the 'event.Listener' event producer. func (gp *Processor) ListenerNotificationParsers() []event.NotificationParserInfo { var pi event.NotificationParserInfo pi.SetScriptHash(gp.designate) pi.SetType(event.TypeFromString(native.DesignationEventName)) pi.SetParser(rolemanagement.ParseDesignate) return []event.NotificationParserInfo{pi} } // ListenerNotificationHandlers for the 'event.Listener' event producer. func (gp *Processor) ListenerNotificationHandlers() []event.NotificationHandlerInfo { var hi event.NotificationHandlerInfo hi.SetScriptHash(gp.designate) hi.SetType(event.TypeFromString(native.DesignationEventName)) hi.SetHandler(gp.HandleAlphabetSync) return []event.NotificationHandlerInfo{hi} } // ListenerNotaryParsers for the 'event.Listener' event producer. func (gp *Processor) ListenerNotaryParsers() []event.NotaryParserInfo { return nil } // ListenerNotaryHandlers for the 'event.Listener' event producer. func (gp *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo { return nil }