forked from TrueCloudLab/frostfs-node
[#249] node: Drop subnet from IR and morph
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
This commit is contained in:
parent
d757d881d0
commit
f07d4158f5
41 changed files with 6 additions and 1903 deletions
|
@ -142,7 +142,6 @@ func setWorkersDefaults(cfg *viper.Viper) {
|
|||
cfg.SetDefault("workers.frostfs", "10")
|
||||
cfg.SetDefault("workers.container", "10")
|
||||
cfg.SetDefault("workers.alphabet", "10")
|
||||
cfg.SetDefault("workers.subnet", "10")
|
||||
}
|
||||
|
||||
func setTimersDefaults(cfg *viper.Viper) {
|
||||
|
@ -163,7 +162,6 @@ func setContractsDefaults(cfg *viper.Viper) {
|
|||
cfg.SetDefault("contracts.audit", "")
|
||||
cfg.SetDefault("contracts.proxy", "")
|
||||
cfg.SetDefault("contracts.processing", "")
|
||||
cfg.SetDefault("contracts.subnet", "")
|
||||
cfg.SetDefault("contracts.proxy", "")
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ FROSTFS_IR_WORKERS_BALANCE=10
|
|||
FROSTFS_IR_WORKERS_CONTAINER=10
|
||||
FROSTFS_IR_WORKERS_NEOFS=10
|
||||
FROSTFS_IR_WORKERS_NETMAP=10
|
||||
FROSTFS_IR_WORKERS_SUBNET=10
|
||||
|
||||
FROSTFS_IR_AUDIT_TIMEOUT_GET=5s
|
||||
FROSTFS_IR_AUDIT_TIMEOUT_HEAD=5s
|
||||
|
@ -74,7 +73,6 @@ FROSTFS_IR_CONTRACTS_CONTAINER=ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6
|
|||
FROSTFS_IR_CONTRACTS_NEOFSID=9f5866decbc751a099e74c7c7bc89f609201755a
|
||||
FROSTFS_IR_CONTRACTS_NETMAP=83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
||||
FROSTFS_IR_CONTRACTS_PROXY=abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
||||
FROSTFS_IR_CONTRACTS_SUBNET=e9266864d3c562c6e17f2bb9cb1392aaa293d93a
|
||||
FROSTFS_IR_CONTRACTS_ALPHABET_AMOUNT=7
|
||||
FROSTFS_IR_CONTRACTS_ALPHABET_AZ=c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
||||
FROSTFS_IR_CONTRACTS_ALPHABET_BUKY=e2ba789320899658b100f331bdebb74474757920
|
||||
|
|
|
@ -83,7 +83,6 @@ workers:
|
|||
container: 10 # Number of workers to process events from container contract in parallel
|
||||
frostfs: 10 # Number of workers to process events from frostfs contracts in parallel
|
||||
netmap: 10 # Number of workers to process events from netmap contract in parallel
|
||||
subnet: 10 # Number of workers to process events from subnet contract in parallel
|
||||
|
||||
audit:
|
||||
timeout:
|
||||
|
@ -116,7 +115,6 @@ contracts:
|
|||
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a # Optional: override address of frostfsid contract in sidechain
|
||||
netmap: 83c600c81d47a1b1b7cf58eb49ae7ee7240dc742 # Optional: override address of netmap contract in sidechain
|
||||
proxy: abc8794bb40a21f2db5f21ae62741eb46c8cad1c # Optional: override address of proxy contract in sidechain; ignore if notary is disabled in sidechain
|
||||
subnet: e9266864d3c562c6e17f2bb9cb1392aaa293d93a # Optional: override address of subnet contract in sidechain
|
||||
alphabet:
|
||||
amount: 7 # Optional: override amount of alphabet contracts
|
||||
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea # Optional: override address of az alphabet contract in sidechain
|
||||
|
|
|
@ -18,7 +18,6 @@ type contracts struct {
|
|||
audit util.Uint160 // in morph
|
||||
proxy util.Uint160 // in morph
|
||||
processing util.Uint160 // in mainnet
|
||||
subnet util.Uint160 // in morph
|
||||
frostfsID util.Uint160 // in morph
|
||||
|
||||
alphabet alphabetContracts // in morph
|
||||
|
@ -60,7 +59,6 @@ func parseContracts(cfg *viper.Viper, morph *client.Client, withoutMainNet, with
|
|||
{"contracts.balance", client.NNSBalanceContractName, &result.balance},
|
||||
{"contracts.container", client.NNSContainerContractName, &result.container},
|
||||
{"contracts.audit", client.NNSAuditContractName, &result.audit},
|
||||
{"contracts.subnet", client.NNSSubnetworkContractName, &result.subnet},
|
||||
{"contracts.frostfsid", client.NNSFrostFSIDContractName, &result.frostfsID},
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
nodevalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation"
|
||||
addrvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/maddress"
|
||||
statevalidation "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/state"
|
||||
subnetvalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement"
|
||||
auditSettlement "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement/audit"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
||||
|
@ -28,7 +27,6 @@ import (
|
|||
frostfsClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
audittask "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/audit/taskmanager"
|
||||
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
||||
|
@ -46,7 +44,6 @@ import (
|
|||
func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
||||
cnrClient *container.Client,
|
||||
alphaSync event.Handler,
|
||||
subnetClient *morphsubnet.Client,
|
||||
auditProcessor *audit.Processor,
|
||||
settlementProcessor *settlement.Processor) error {
|
||||
locodeValidator, err := s.newLocodeValidator(cfg)
|
||||
|
@ -54,11 +51,6 @@ func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
|||
return err
|
||||
}
|
||||
|
||||
subnetValidator, err := subnetvalidator.New(
|
||||
subnetvalidator.Prm{
|
||||
SubnetClient: subnetClient,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -94,10 +86,8 @@ func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
|||
&netMapCandidateStateValidator,
|
||||
addrvalidator.New(),
|
||||
locodeValidator,
|
||||
subnetValidator,
|
||||
),
|
||||
NotaryDisabled: s.sideNotaryConfig.disabled,
|
||||
SubnetContract: &s.contracts.subnet,
|
||||
|
||||
NodeStateSettings: netSettings,
|
||||
})
|
||||
|
@ -349,27 +339,6 @@ func (s *Server) initTimers(cfg *viper.Viper, processors *serverProcessors, morp
|
|||
s.addBlockTimer(emissionTimer)
|
||||
}
|
||||
|
||||
func (s *Server) createMorphSubnetClient() (*morphsubnet.Client, error) {
|
||||
// initialize morph client of Subnet contract
|
||||
clientMode := morphsubnet.NotaryAlphabet
|
||||
|
||||
if s.sideNotaryConfig.disabled {
|
||||
clientMode = morphsubnet.NonNotary
|
||||
}
|
||||
|
||||
subnetInitPrm := morphsubnet.InitPrm{}
|
||||
subnetInitPrm.SetBaseClient(s.morphClient)
|
||||
subnetInitPrm.SetContractAddress(s.contracts.subnet)
|
||||
subnetInitPrm.SetMode(clientMode)
|
||||
|
||||
subnetClient := &morphsubnet.Client{}
|
||||
err := subnetClient.Init(subnetInitPrm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not initialize subnet client: %w", err)
|
||||
}
|
||||
return subnetClient, nil
|
||||
}
|
||||
|
||||
func (s *Server) initAlphabetProcessor(cfg *viper.Viper) (*alphabet.Processor, error) {
|
||||
parsedWallets, err := parseWalletAddressesFromStrings(cfg.GetStringSlice("emit.extra_wallets"))
|
||||
if err != nil {
|
||||
|
@ -400,7 +369,7 @@ func (s *Server) initAlphabetProcessor(cfg *viper.Viper) (*alphabet.Processor, e
|
|||
}
|
||||
|
||||
func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.Client,
|
||||
frostfsIDClient *frostfsid.Client, subnetClient *morphsubnet.Client) error {
|
||||
frostfsIDClient *frostfsid.Client) error {
|
||||
// container processor
|
||||
containerProcessor, err := cont.New(&cont.Params{
|
||||
Log: s.log,
|
||||
|
@ -410,7 +379,6 @@ func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.C
|
|||
FrostFSIDClient: frostfsIDClient,
|
||||
NetworkState: s.netmapClient,
|
||||
NotaryDisabled: s.sideNotaryConfig.disabled,
|
||||
SubnetClient: subnetClient,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -515,10 +483,9 @@ func (s *Server) initGRPCServer(cfg *viper.Viper) error {
|
|||
}
|
||||
|
||||
type serverMorphClients struct {
|
||||
CnrClient *container.Client
|
||||
FrostFSIDClient *frostfsid.Client
|
||||
FrostFSClient *frostfsClient.Client
|
||||
MorphSubnetClient *morphsubnet.Client
|
||||
CnrClient *container.Client
|
||||
FrostFSIDClient *frostfsid.Client
|
||||
FrostFSClient *frostfsClient.Client
|
||||
}
|
||||
|
||||
func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
||||
|
@ -574,11 +541,6 @@ func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
result.MorphSubnetClient, err = s.createMorphSubnetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
@ -624,12 +586,12 @@ func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClien
|
|||
return nil, err
|
||||
}
|
||||
|
||||
err = s.initNetmapProcessor(cfg, morphClients.CnrClient, alphaSync, morphClients.MorphSubnetClient, auditProcessor, result.SettlementProcessor)
|
||||
err = s.initNetmapProcessor(cfg, morphClients.CnrClient, alphaSync, auditProcessor, result.SettlementProcessor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.initContainerProcessor(cfg, morphClients.CnrClient, morphClients.FrostFSIDClient, morphClients.MorphSubnetClient)
|
||||
err = s.initContainerProcessor(cfg, morphClients.CnrClient, morphClients.FrostFSIDClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -100,8 +100,6 @@ type (
|
|||
// should report start errors
|
||||
// to the application.
|
||||
runners []func(chan<- error) error
|
||||
|
||||
subnetHandler
|
||||
}
|
||||
|
||||
chainParams struct {
|
||||
|
@ -400,10 +398,6 @@ func New(ctx context.Context, log *logger.Logger, cfg *viper.Viper, errChan chan
|
|||
return nil, err
|
||||
}
|
||||
|
||||
server.initSubnet(subnetConfig{
|
||||
queueSize: cfg.GetUint32("workers.subnet"),
|
||||
})
|
||||
|
||||
server.initMetrics(cfg)
|
||||
|
||||
return server, nil
|
||||
|
|
|
@ -5,13 +5,11 @@ import (
|
|||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -77,12 +75,6 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
|||
return fmt.Errorf("auth container creation: %w", err)
|
||||
}
|
||||
|
||||
// check owner allowance in the subnetwork
|
||||
err = checkSubnet(cp.subnetClient, cnr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("incorrect subnetwork: %w", err)
|
||||
}
|
||||
|
||||
// check homomorphic hashing setting
|
||||
err = checkHomomorphicHashing(cp.netState, cnr)
|
||||
if err != nil {
|
||||
|
@ -222,29 +214,6 @@ func checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkSubnet(subCli *morphsubnet.Client, cnr containerSDK.Container) error {
|
||||
prm := morphsubnet.UserAllowedPrm{}
|
||||
|
||||
subID := cnr.PlacementPolicy().Subnet()
|
||||
if subnetid.IsZero(subID) {
|
||||
return nil
|
||||
}
|
||||
|
||||
prm.SetID(subID.Marshal())
|
||||
prm.SetClient(cnr.Owner().WalletBytes())
|
||||
|
||||
res, err := subCli.UserAllowed(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not check user in contract: %w", err)
|
||||
}
|
||||
|
||||
if !res.Allowed() {
|
||||
return fmt.Errorf("user is not allowed to create containers in %v subnetwork", subID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkHomomorphicHashing(ns NetworkState, cnr containerSDK.Container) error {
|
||||
netSetting, err := ns.HomomorphicHashDisabled()
|
||||
if err != nil {
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||
|
@ -29,7 +28,6 @@ type (
|
|||
alphabetState AlphabetState
|
||||
cnrClient *container.Client // notary must be enabled
|
||||
idClient *frostfsid.Client
|
||||
subnetClient *morphsubnet.Client
|
||||
netState NetworkState
|
||||
notaryDisabled bool
|
||||
}
|
||||
|
@ -41,7 +39,6 @@ type (
|
|||
AlphabetState AlphabetState
|
||||
ContainerClient *container.Client
|
||||
FrostFSIDClient *frostfsid.Client
|
||||
SubnetClient *morphsubnet.Client
|
||||
NetworkState NetworkState
|
||||
NotaryDisabled bool
|
||||
}
|
||||
|
@ -85,8 +82,6 @@ func New(p *Params) (*Processor, error) {
|
|||
return nil, errors.New("ir/container: FrostFS ID client is not set")
|
||||
case p.NetworkState == nil:
|
||||
return nil, errors.New("ir/container: network state is not set")
|
||||
case p.SubnetClient == nil:
|
||||
return nil, errors.New("ir/container: subnet client is not set")
|
||||
}
|
||||
|
||||
p.Log.Debug(logs.ContainerContainerWorkerPool, zap.Int("size", p.PoolSize))
|
||||
|
@ -104,7 +99,6 @@ func New(p *Params) (*Processor, error) {
|
|||
idClient: p.FrostFSIDClient,
|
||||
netState: p.NetworkState,
|
||||
notaryDisabled: p.NotaryDisabled,
|
||||
subnetClient: p.SubnetClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
timerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||
subnetevents "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -101,22 +100,3 @@ func (np *Processor) handleCleanupTick(ev event.Event) {
|
|||
zap.Int("capacity", np.pool.Cap()))
|
||||
}
|
||||
}
|
||||
|
||||
func (np *Processor) handleRemoveNode(ev event.Event) {
|
||||
removeNode := ev.(subnetevents.RemoveNode)
|
||||
|
||||
np.log.Info(logs.Notification,
|
||||
zap.String("type", "remove node from subnet"),
|
||||
zap.String("subnetID", hex.EncodeToString(removeNode.SubnetworkID())),
|
||||
zap.String("key", hex.EncodeToString(removeNode.Node())),
|
||||
)
|
||||
|
||||
err := np.pool.Submit(func() {
|
||||
np.processRemoveSubnetNode(removeNode)
|
||||
})
|
||||
if err != nil {
|
||||
// there system can be moved into controlled degradation stage
|
||||
np.log.Warn(logs.NetmapNetmapWorkerPoolDrained,
|
||||
zap.Int("capacity", np.pool.Cap()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
package subnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
)
|
||||
|
||||
// VerifyAndUpdate calls subnet contract's `NodeAllowed` method.
|
||||
// Removes subnets that have not been approved by the contract.
|
||||
func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error {
|
||||
prm := morphsubnet.NodeAllowedPrm{}
|
||||
|
||||
err := n.IterateSubnets(func(id subnetid.ID) error {
|
||||
// every node can be bootstrapped
|
||||
// to the zero subnetwork
|
||||
if subnetid.IsZero(id) {
|
||||
return nil
|
||||
}
|
||||
|
||||
prm.SetID(id.Marshal())
|
||||
prm.SetNode(n.PublicKey())
|
||||
|
||||
res, err := v.subnetClient.NodeAllowed(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not call `NodeAllowed` contract method: %w", err)
|
||||
}
|
||||
|
||||
if !res.Allowed() {
|
||||
return netmap.ErrRemoveSubnet
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not verify subnet entrance of the node: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package subnet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
)
|
||||
|
||||
// Validator is an utility that verifies node subnet
|
||||
// allowance.
|
||||
//
|
||||
// For correct operation, Validator must be created
|
||||
// using the constructor (New). After successful creation,
|
||||
// the Validator is immediately ready to work through API.
|
||||
type Validator struct {
|
||||
subnetClient *morphsubnet.Client
|
||||
}
|
||||
|
||||
// Prm groups the required parameters of the Validator's constructor.
|
||||
//
|
||||
// All values must comply with the requirements imposed on them.
|
||||
// Passing incorrect parameter values will result in constructor
|
||||
// failure (error or panic depending on the implementation).
|
||||
type Prm struct {
|
||||
SubnetClient *morphsubnet.Client
|
||||
}
|
||||
|
||||
// New creates a new instance of the Validator.
|
||||
//
|
||||
// The created Validator does not require additional
|
||||
// initialization and is completely ready for work.
|
||||
func New(prm Prm) (*Validator, error) {
|
||||
switch {
|
||||
case prm.SubnetClient == nil:
|
||||
return nil, errors.New("ir/nodeValidator: subnet client is not set")
|
||||
}
|
||||
|
||||
return &Validator{
|
||||
subnetClient: prm.SubnetClient,
|
||||
}, nil
|
||||
}
|
|
@ -1,15 +1,12 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||
subnetEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -139,74 +136,3 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
|
|||
np.log.Error(logs.NetmapCantInvokeNetmapUpdatePeer, zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (np *Processor) processRemoveSubnetNode(ev subnetEvent.RemoveNode) {
|
||||
if !np.alphabetState.IsAlphabet() {
|
||||
np.log.Info(logs.NetmapNonAlphabetModeIgnoreRemoveNodeFromSubnetNotification)
|
||||
return
|
||||
}
|
||||
|
||||
candidates, err := np.netmapClient.GetCandidates()
|
||||
if err != nil {
|
||||
np.log.Warn(logs.NetmapCouldNotGetNetworkMapCandidates,
|
||||
zap.Error(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
rawSubnet := ev.SubnetworkID()
|
||||
var subnetToRemoveFrom subnetid.ID
|
||||
|
||||
err = subnetToRemoveFrom.Unmarshal(rawSubnet)
|
||||
if err != nil {
|
||||
np.log.Warn(logs.NetmapCouldNotUnmarshalSubnetID,
|
||||
zap.Error(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if subnetid.IsZero(subnetToRemoveFrom) {
|
||||
np.log.Warn(logs.NetmapGotZeroSubnetInRemoveNodeNotification)
|
||||
return
|
||||
}
|
||||
|
||||
for i := range candidates {
|
||||
if !bytes.Equal(candidates[i].PublicKey(), ev.Node()) {
|
||||
continue
|
||||
}
|
||||
|
||||
err = candidates[i].IterateSubnets(func(subNetID subnetid.ID) error {
|
||||
if subNetID.Equals(subnetToRemoveFrom) {
|
||||
return netmap.ErrRemoveSubnet
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
np.log.Warn(logs.NetmapCouldNotIterateOverSubnetworksOfTheNode, zap.Error(err))
|
||||
np.log.Info(logs.NetmapVoteToRemoveNodeFromNetmap, zap.String("key", hex.EncodeToString(ev.Node())))
|
||||
|
||||
prm := netmapclient.UpdatePeerPrm{}
|
||||
prm.SetKey(ev.Node())
|
||||
prm.SetHash(ev.TxHash())
|
||||
|
||||
err = np.netmapClient.UpdatePeerState(prm)
|
||||
if err != nil {
|
||||
np.log.Error(logs.NetmapCouldNotInvokeNetmapUpdateState, zap.Error(err))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
prm := netmapclient.AddPeerPrm{}
|
||||
prm.SetNodeInfo(candidates[i])
|
||||
prm.SetHash(ev.TxHash())
|
||||
|
||||
err = np.netmapClient.AddPeer(prm)
|
||||
if err != nil {
|
||||
np.log.Error(logs.NetmapCouldNotInvokeNetmapAddPeer, zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,9 @@ import (
|
|||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
||||
subnetEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -65,8 +63,6 @@ type (
|
|||
netmapClient *nmClient.Client
|
||||
containerWrp *container.Client
|
||||
|
||||
subnetContract util.Uint160
|
||||
|
||||
netmapSnapshot cleanupTable
|
||||
|
||||
handleNewAudit event.Handler
|
||||
|
@ -92,7 +88,6 @@ type (
|
|||
CleanupEnabled bool
|
||||
CleanupThreshold uint64 // in epochs
|
||||
ContainerWrapper *container.Client
|
||||
SubnetContract *util.Uint160
|
||||
|
||||
HandleAudit event.Handler
|
||||
AuditSettlementsHandler event.Handler
|
||||
|
@ -111,7 +106,6 @@ const (
|
|||
newEpochNotification = "NewEpoch"
|
||||
addPeerNotification = "AddPeer"
|
||||
updatePeerStateNotification = "UpdateState"
|
||||
removeNodeNotification = "RemoveNode"
|
||||
)
|
||||
|
||||
// New creates network map contract processor instance.
|
||||
|
@ -137,8 +131,6 @@ func New(p *Params) (*Processor, error) {
|
|||
return nil, errors.New("ir/netmap: container contract wrapper is not set")
|
||||
case p.NodeValidator == nil:
|
||||
return nil, errors.New("ir/netmap: node validator is not set")
|
||||
case p.SubnetContract == nil:
|
||||
return nil, errors.New("ir/netmap: subnet contract script hash is not set")
|
||||
case p.NodeStateSettings == nil:
|
||||
return nil, errors.New("ir/netmap: node state settings is not set")
|
||||
}
|
||||
|
@ -160,7 +152,6 @@ func New(p *Params) (*Processor, error) {
|
|||
containerWrp: p.ContainerWrapper,
|
||||
netmapSnapshot: newCleanupTable(p.CleanupEnabled, p.CleanupThreshold),
|
||||
handleNewAudit: p.HandleAudit,
|
||||
subnetContract: *p.SubnetContract,
|
||||
|
||||
handleAuditSettlements: p.AuditSettlementsHandler,
|
||||
|
||||
|
@ -182,13 +173,6 @@ func (np *Processor) ListenerNotificationParsers() []event.NotificationParserInf
|
|||
|
||||
var p event.NotificationParserInfo
|
||||
|
||||
// remove node from subnetwork event
|
||||
p.SetScriptHash(np.subnetContract)
|
||||
p.SetType(removeNodeNotification)
|
||||
p.SetParser(subnetEvent.ParseRemoveNode)
|
||||
|
||||
parsers = append(parsers, p)
|
||||
|
||||
p.SetScriptHash(np.netmapClient.ContractAddress())
|
||||
|
||||
// new epoch event
|
||||
|
@ -219,13 +203,6 @@ func (np *Processor) ListenerNotificationHandlers() []event.NotificationHandlerI
|
|||
|
||||
var i event.NotificationHandlerInfo
|
||||
|
||||
// remove node from subnetwork event
|
||||
i.SetScriptHash(np.subnetContract)
|
||||
i.SetType(removeNodeNotification)
|
||||
i.SetHandler(np.handleRemoveNode)
|
||||
|
||||
handlers = append(handlers, i)
|
||||
|
||||
i.SetScriptHash(np.netmapClient.ContractAddress())
|
||||
|
||||
// new epoch handler
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
)
|
||||
|
||||
// common interface of subnet notifications with subnet ID.
|
||||
type eventWithID interface {
|
||||
// ReadID reads identifier of the subnet.
|
||||
ReadID(*subnetid.ID) error
|
||||
}
|
||||
|
||||
// an error which is returned on zero subnet operation attempt.
|
||||
type zeroSubnetOp struct {
|
||||
op string
|
||||
}
|
||||
|
||||
func (x zeroSubnetOp) Error() string {
|
||||
return fmt.Sprintf("zero subnet %s", x.op)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
|
||||
type idEvent struct {
|
||||
id subnetid.ID
|
||||
|
||||
idErr error
|
||||
}
|
||||
|
||||
func (x idEvent) ReadID(id *subnetid.ID) error {
|
||||
if x.idErr != nil {
|
||||
return x.idErr
|
||||
}
|
||||
|
||||
*id = x.id
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
)
|
||||
|
||||
// Put represents a notification about FrostFS subnet creation.
|
||||
// Generated by a contract when intending to create a subnet.
|
||||
type Put interface {
|
||||
// Contains the ID of the subnet to be created.
|
||||
eventWithID
|
||||
|
||||
// ReadCreator reads the user ID of the subnet creator.
|
||||
// Returns an error if the ID is missing.
|
||||
ReadCreator(id *user.ID) error
|
||||
|
||||
// ReadInfo reads information about a subnet to be created.
|
||||
ReadInfo(info *subnet.Info) error
|
||||
}
|
||||
|
||||
// PutValidator asserts intent to create a subnet.
|
||||
type PutValidator struct{}
|
||||
|
||||
// errDiffOwner is returned when the subnet owners differ.
|
||||
var errDiffOwner = errors.New("diff subnet owners")
|
||||
|
||||
// errDiffID is returned when the subnet IDs differ.
|
||||
var errDiffID = errors.New("diff subnet IDs")
|
||||
|
||||
// Assert processes the attempt to create a subnet. It approves the creation through nil return.
|
||||
//
|
||||
// All read errors of Put are forwarded.
|
||||
//
|
||||
// It returns an error on:
|
||||
// - zero subnet creation;
|
||||
// - empty ID or different from the one wired into info;
|
||||
// - empty owner ID or different from the one wired into info.
|
||||
func (x PutValidator) Assert(event Put) error {
|
||||
var err error
|
||||
|
||||
// read ID
|
||||
var id subnetid.ID
|
||||
if err = event.ReadID(&id); err != nil {
|
||||
return fmt.Errorf("read ID: %w", err)
|
||||
}
|
||||
|
||||
// prevent zero subnet creation
|
||||
if subnetid.IsZero(id) {
|
||||
return zeroSubnetOp{
|
||||
op: "creation",
|
||||
}
|
||||
}
|
||||
|
||||
// read creator's user ID in FrostFS system
|
||||
var creator user.ID
|
||||
if err = event.ReadCreator(&creator); err != nil {
|
||||
return fmt.Errorf("read creator: %w", err)
|
||||
}
|
||||
|
||||
// read information about the subnet
|
||||
var info subnet.Info
|
||||
if err = event.ReadInfo(&info); err != nil {
|
||||
return fmt.Errorf("read info: %w", err)
|
||||
}
|
||||
|
||||
// check if the explicit ID equals to the one from info
|
||||
if !subnet.AssertReference(info, id) {
|
||||
return errDiffID
|
||||
}
|
||||
|
||||
// check if the explicit creator equals to the one from info
|
||||
if !subnet.AssertOwnership(info, creator) {
|
||||
return errDiffOwner
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
)
|
||||
|
||||
type put struct {
|
||||
idEvent
|
||||
|
||||
creator user.ID
|
||||
|
||||
creatorErr error
|
||||
|
||||
info subnet.Info
|
||||
|
||||
infoErr error
|
||||
}
|
||||
|
||||
func (x put) ReadCreator(id *user.ID) error {
|
||||
if x.creatorErr != nil {
|
||||
return x.creatorErr
|
||||
}
|
||||
|
||||
*id = x.creator
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x put) ReadInfo(info *subnet.Info) error {
|
||||
if x.infoErr != nil {
|
||||
return x.infoErr
|
||||
}
|
||||
|
||||
*info = x.info
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestPutValidator_Assert(t *testing.T) {
|
||||
var (
|
||||
v PutValidator
|
||||
|
||||
e put
|
||||
|
||||
err error
|
||||
)
|
||||
|
||||
// read ID error
|
||||
e.idErr = errors.New("id err")
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorIs(t, err, e.idErr)
|
||||
|
||||
e.idErr = nil
|
||||
|
||||
// zero subnet ID
|
||||
subnetid.MakeZero(&e.id)
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorAs(t, err, new(zeroSubnetOp))
|
||||
|
||||
const idNum = 13
|
||||
e.id.SetNumeric(idNum)
|
||||
|
||||
// read creator error
|
||||
e.creatorErr = errors.New("creator err")
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorIs(t, err, e.creatorErr)
|
||||
|
||||
e.creatorErr = nil
|
||||
|
||||
// read info error
|
||||
e.infoErr = errors.New("info err")
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorIs(t, err, e.infoErr)
|
||||
|
||||
e.infoErr = nil
|
||||
|
||||
// diff explicit ID and the one in info
|
||||
var id2 subnetid.ID
|
||||
|
||||
id2.SetNumeric(idNum + 1)
|
||||
|
||||
e.info.SetID(id2)
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorIs(t, err, errDiffID)
|
||||
|
||||
e.info.SetID(e.id)
|
||||
|
||||
// diff explicit creator and the one in info
|
||||
creator2 := *usertest.ID()
|
||||
|
||||
e.info.SetOwner(creator2)
|
||||
|
||||
err = v.Assert(e)
|
||||
require.ErrorIs(t, err, errDiffOwner)
|
||||
|
||||
e.info.SetOwner(e.creator)
|
||||
|
||||
err = v.Assert(e)
|
||||
require.NoError(t, err)
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
package innerring
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
irsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/subnet"
|
||||
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
morphsubnet "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
subnetevents "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
neogoutil "github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// IR server's component to handle Subnet contract notifications.
|
||||
type subnetHandler struct {
|
||||
workerPool util.WorkerPool
|
||||
|
||||
morphClient morphsubnet.Client
|
||||
|
||||
putValidator irsubnet.PutValidator
|
||||
}
|
||||
|
||||
// configuration of subnet component.
|
||||
type subnetConfig struct {
|
||||
queueSize uint32
|
||||
}
|
||||
|
||||
// makes IR server to catch Subnet notifications from the sidechain listener,
|
||||
// and to release the corresponding processing queue on stop.
|
||||
func (s *Server) initSubnet(cfg subnetConfig) {
|
||||
s.registerStarter(func() error {
|
||||
var err error
|
||||
|
||||
// initialize queue for processing of the events from Subnet contract
|
||||
s.subnetHandler.workerPool, err = ants.NewPool(int(cfg.queueSize), ants.WithNonblocking(true))
|
||||
if err != nil {
|
||||
return fmt.Errorf("subnet queue initialization: %w", err)
|
||||
}
|
||||
|
||||
// initialize morph client of Subnet contract
|
||||
clientMode := morphsubnet.NotaryAlphabet
|
||||
|
||||
if s.sideNotaryConfig.disabled {
|
||||
clientMode = morphsubnet.NonNotary
|
||||
}
|
||||
|
||||
var initPrm morphsubnet.InitPrm
|
||||
|
||||
initPrm.SetBaseClient(s.morphClient)
|
||||
initPrm.SetContractAddress(s.contracts.subnet)
|
||||
initPrm.SetMode(clientMode)
|
||||
|
||||
err = s.subnetHandler.morphClient.Init(initPrm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("init morph subnet client: %w", err)
|
||||
}
|
||||
|
||||
s.listenSubnet()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
s.registerCloser(func() error {
|
||||
s.stopSubnet()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// releases the Subnet contract notification processing queue.
|
||||
func (s *Server) stopSubnet() {
|
||||
s.workerPool.Release()
|
||||
}
|
||||
|
||||
// names of listened notification events from Subnet contract.
|
||||
const (
|
||||
subnetCreateEvName = "Put"
|
||||
subnetRemoveEvName = "Delete"
|
||||
notarySubnetCreateEvName = "put"
|
||||
)
|
||||
|
||||
// makes the IR server to listen to notifications of Subnet contract.
|
||||
// All required resources must be initialized before (initSubnet).
|
||||
// It works in one of two modes (configured): notary and non-notary.
|
||||
//
|
||||
// All handlers are executed only if the local node is an alphabet one.
|
||||
//
|
||||
// Events (notary):
|
||||
// - put (parser: subnetevents.ParseNotaryPut, handler: catchSubnetCreation);
|
||||
// - Delete (parser: subnetevents.ParseDelete, handler: catchSubnetCreation).
|
||||
//
|
||||
// Events (non-notary):
|
||||
// - Put (parser: subnetevents.ParsePut, handler: catchSubnetCreation);
|
||||
// - Delete (parser: subnetevents.ParseDelete, handler: catchSubnetCreation).
|
||||
func (s *Server) listenSubnet() {
|
||||
if s.sideNotaryConfig.disabled {
|
||||
s.listenSubnetWithoutNotary()
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
parserInfo event.NotaryParserInfo
|
||||
handlerInfo event.NotaryHandlerInfo
|
||||
)
|
||||
|
||||
parserInfo.SetScriptHash(s.contracts.subnet)
|
||||
handlerInfo.SetScriptHash(s.contracts.subnet)
|
||||
|
||||
listenNotaryEvent := func(notifyName string, parser event.NotaryParser, handler event.Handler) {
|
||||
notifyTyp := event.NotaryTypeFromString(notifyName)
|
||||
|
||||
parserInfo.SetMempoolType(mempoolevent.TransactionAdded)
|
||||
handlerInfo.SetMempoolType(mempoolevent.TransactionAdded)
|
||||
|
||||
parserInfo.SetParser(parser)
|
||||
handlerInfo.SetHandler(handler)
|
||||
|
||||
parserInfo.SetRequestType(notifyTyp)
|
||||
handlerInfo.SetRequestType(notifyTyp)
|
||||
|
||||
s.morphListener.SetNotaryParser(parserInfo)
|
||||
s.morphListener.RegisterNotaryHandler(handlerInfo)
|
||||
}
|
||||
|
||||
// subnet creation
|
||||
listenNotaryEvent(notarySubnetCreateEvName, subnetevents.ParseNotaryPut, s.onlyAlphabetEventHandler(s.catchSubnetCreation))
|
||||
// subnet removal
|
||||
listenNotifySubnetEvent(s, subnetRemoveEvName, subnetevents.ParseDelete, s.onlyAlphabetEventHandler(s.catchSubnetRemoval))
|
||||
}
|
||||
|
||||
func (s *Server) listenSubnetWithoutNotary() {
|
||||
// subnet creation
|
||||
listenNotifySubnetEvent(s, subnetCreateEvName, subnetevents.ParsePut, s.onlyAlphabetEventHandler(s.catchSubnetCreation))
|
||||
// subnet removal
|
||||
listenNotifySubnetEvent(s, subnetRemoveEvName, subnetevents.ParseDelete, s.onlyAlphabetEventHandler(s.catchSubnetRemoval))
|
||||
}
|
||||
|
||||
func listenNotifySubnetEvent(s *Server, notifyName string, parser event.NotificationParser, handler event.Handler) {
|
||||
var (
|
||||
parserInfo event.NotificationParserInfo
|
||||
handlerInfo event.NotificationHandlerInfo
|
||||
)
|
||||
|
||||
parserInfo.SetScriptHash(s.contracts.subnet)
|
||||
handlerInfo.SetScriptHash(s.contracts.subnet)
|
||||
|
||||
notifyTyp := event.TypeFromString(notifyName)
|
||||
|
||||
parserInfo.SetType(notifyTyp)
|
||||
handlerInfo.SetType(notifyTyp)
|
||||
|
||||
parserInfo.SetParser(parser)
|
||||
handlerInfo.SetHandler(handler)
|
||||
|
||||
s.morphListener.SetNotificationParser(parserInfo)
|
||||
s.morphListener.RegisterNotificationHandler(handlerInfo)
|
||||
}
|
||||
|
||||
// catchSubnetCreation catches event of subnet creation from listener and queues the processing.
|
||||
func (s *Server) catchSubnetCreation(e event.Event) {
|
||||
err := s.subnetHandler.workerPool.Submit(func() {
|
||||
s.handleSubnetCreation(e)
|
||||
})
|
||||
if err != nil {
|
||||
s.log.Error(logs.InnerringSubnetCreationQueueFailure,
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// implements irsubnet.Put event interface required by irsubnet.PutValidator.
|
||||
type putSubnetEvent struct {
|
||||
ev subnetevents.Put
|
||||
}
|
||||
|
||||
// ReadID unmarshals the subnet ID from a binary FrostFS API protocol's format.
|
||||
func (x putSubnetEvent) ReadID(id *subnetid.ID) error {
|
||||
return id.Unmarshal(x.ev.ID())
|
||||
}
|
||||
|
||||
var errMissingSubnetOwner = errors.New("missing subnet owner")
|
||||
|
||||
// ReadCreator unmarshals the subnet creator from a binary FrostFS API protocol's format.
|
||||
// Returns an error if the byte array is empty.
|
||||
func (x putSubnetEvent) ReadCreator(id *user.ID) error {
|
||||
data := x.ev.Owner()
|
||||
|
||||
if len(data) == 0 {
|
||||
return errMissingSubnetOwner
|
||||
}
|
||||
|
||||
key, err := keys.NewPublicKeyFromBytes(data, elliptic.P256())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.IDFromKey(id, (ecdsa.PublicKey)(*key))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadInfo unmarshal the subnet info from a binary FrostFS API protocol's format.
|
||||
func (x putSubnetEvent) ReadInfo(info *subnet.Info) error {
|
||||
return info.Unmarshal(x.ev.Info())
|
||||
}
|
||||
|
||||
// handleSubnetCreation handles an event of subnet creation parsed via subnetevents.ParsePut.
|
||||
//
|
||||
// Validates the event using irsubnet.PutValidator. Logs message about (dis)agreement.
|
||||
func (s *Server) handleSubnetCreation(e event.Event) {
|
||||
putEv := e.(subnetevents.Put) // panic occurs only if we registered handler incorrectly
|
||||
|
||||
err := s.subnetHandler.putValidator.Assert(putSubnetEvent{
|
||||
ev: putEv,
|
||||
})
|
||||
if err != nil {
|
||||
s.log.Info(logs.InnerringDiscardSubnetCreation,
|
||||
zap.String("reason", err.Error()),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
notaryMainTx := putEv.NotaryMainTx()
|
||||
|
||||
isNotary := notaryMainTx != nil
|
||||
if isNotary {
|
||||
// re-sign notary request
|
||||
err = s.morphClient.NotarySignAndInvokeTX(notaryMainTx)
|
||||
} else {
|
||||
// send new transaction
|
||||
var prm morphsubnet.PutPrm
|
||||
|
||||
prm.SetID(putEv.ID())
|
||||
prm.SetOwner(putEv.Owner())
|
||||
prm.SetInfo(putEv.Info())
|
||||
prm.SetTxHash(putEv.TxHash())
|
||||
|
||||
_, err = s.subnetHandler.morphClient.Put(prm)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
s.log.Error(logs.InnerringApproveSubnetCreation,
|
||||
zap.Bool("notary", isNotary),
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// catchSubnetRemoval catches an event of subnet removal from listener and queues the processing.
|
||||
func (s *Server) catchSubnetRemoval(e event.Event) {
|
||||
err := s.subnetHandler.workerPool.Submit(func() {
|
||||
s.handleSubnetRemoval(e)
|
||||
})
|
||||
if err != nil {
|
||||
s.log.Error(logs.InnerringSubnetRemovalHandlingFailure,
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// handleSubnetRemoval handles event of subnet removal parsed via subnetevents.ParseDelete.
|
||||
func (s *Server) handleSubnetRemoval(e event.Event) {
|
||||
delEv := e.(subnetevents.Delete) // panic occurs only if we registered handler incorrectly
|
||||
|
||||
// handle subnet changes in netmap
|
||||
|
||||
candidates, err := s.netmapClient.GetCandidates()
|
||||
if err != nil {
|
||||
s.log.Error(logs.InnerringGettingNetmapCandidates,
|
||||
zap.Error(err),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var removedID subnetid.ID
|
||||
err = removedID.Unmarshal(delEv.ID())
|
||||
if err != nil {
|
||||
s.log.Error(logs.InnerringUnmarshallingRemovedSubnetID,
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
for i := range candidates {
|
||||
s.processCandidate(delEv.TxHash(), removedID, candidates[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) processCandidate(txHash neogoutil.Uint256, removedID subnetid.ID, c netmap.NodeInfo) {
|
||||
removeSubnet := false
|
||||
log := s.log.With(
|
||||
zap.String("public_key", netmap.StringifyPublicKey(c)),
|
||||
zap.String("removed_subnet", removedID.String()),
|
||||
)
|
||||
|
||||
err := c.IterateSubnets(func(id subnetid.ID) error {
|
||||
if removedID.Equals(id) {
|
||||
removeSubnet = true
|
||||
return netmap.ErrRemoveSubnet
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(logs.InnerringIteratingNodesSubnets, zap.Error(err))
|
||||
log.Debug(logs.InnerringRemovingNodeFromNetmapCandidates)
|
||||
|
||||
var updateStatePrm netmapclient.UpdatePeerPrm
|
||||
updateStatePrm.SetKey(c.PublicKey())
|
||||
updateStatePrm.SetHash(txHash)
|
||||
|
||||
err = s.netmapClient.UpdatePeerState(updateStatePrm)
|
||||
if err != nil {
|
||||
log.Error(logs.InnerringRemovingNodeFromCandidates,
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// remove subnet from node's information
|
||||
// if it contains removed subnet
|
||||
if removeSubnet {
|
||||
log.Debug(logs.InnerringRemovingSubnetFromTheNode)
|
||||
|
||||
var addPeerPrm netmapclient.AddPeerPrm
|
||||
addPeerPrm.SetNodeInfo(c)
|
||||
addPeerPrm.SetHash(txHash)
|
||||
|
||||
err = s.netmapClient.AddPeer(addPeerPrm)
|
||||
if err != nil {
|
||||
log.Error(logs.InnerringUpdatingSubnetInfo,
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,8 +32,6 @@ const (
|
|||
NNSNetmapContractName = "netmap.frostfs"
|
||||
// NNSProxyContractName is a name of the proxy contract in NNS.
|
||||
NNSProxyContractName = "proxy.frostfs"
|
||||
// NNSSubnetworkContractName is a name of the subnet contract in NNS.
|
||||
NNSSubnetworkContractName = "subnet.frostfs"
|
||||
// NNSGroupKeyName is a name for the FrostFS group key record in NNS.
|
||||
NNSGroupKeyName = "group.frostfs"
|
||||
)
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
|
||||
// ManageAdminsPrm groups parameters of administer methods of Subnet contract.
|
||||
//
|
||||
// Zero value adds node admin. Subnet, key and group must be specified via setters.
|
||||
type ManageAdminsPrm struct {
|
||||
// remove or add admin
|
||||
rm bool
|
||||
|
||||
// client or node admin
|
||||
client bool
|
||||
|
||||
subnet []byte
|
||||
|
||||
admin []byte
|
||||
|
||||
group []byte
|
||||
}
|
||||
|
||||
// SetRemove marks admin to be removed. By default, admin is added.
|
||||
func (x *ManageAdminsPrm) SetRemove() {
|
||||
x.rm = true
|
||||
}
|
||||
|
||||
// SetClient switches to client admin. By default, node admin is modified.
|
||||
func (x *ManageAdminsPrm) SetClient() {
|
||||
x.client = true
|
||||
}
|
||||
|
||||
// SetSubnet sets identifier of the subnet in a binary FrostFS API protocol format.
|
||||
func (x *ManageAdminsPrm) SetSubnet(id []byte) {
|
||||
x.subnet = id
|
||||
}
|
||||
|
||||
// SetAdmin sets admin's public key in a binary format.
|
||||
func (x *ManageAdminsPrm) SetAdmin(key []byte) {
|
||||
x.admin = key
|
||||
}
|
||||
|
||||
// SetGroup sets identifier of the client group in a binary FrostFS API protocol format.
|
||||
// Makes sense only for client admins (see ManageAdminsPrm.SetClient).
|
||||
func (x *ManageAdminsPrm) SetGroup(id []byte) {
|
||||
x.group = id
|
||||
}
|
||||
|
||||
// ManageAdminsRes groups the resulting values of node administer methods of Subnet contract.
|
||||
type ManageAdminsRes struct{}
|
||||
|
||||
// ManageAdmins manages admin list of the FrostFS subnet through Subnet contract calls.
|
||||
func (x Client) ManageAdmins(prm ManageAdminsPrm) (*ManageAdminsPrm, error) {
|
||||
var method string
|
||||
|
||||
args := make([]any, 1, 3)
|
||||
args[0] = prm.subnet
|
||||
|
||||
if prm.client {
|
||||
args = append(args, prm.group, prm.admin)
|
||||
|
||||
if prm.rm {
|
||||
method = removeClientAdminMethod
|
||||
} else {
|
||||
method = addClientAdminMethod
|
||||
}
|
||||
} else {
|
||||
args = append(args, prm.admin)
|
||||
|
||||
if prm.rm {
|
||||
method = removeNodeAdminMethod
|
||||
} else {
|
||||
method = addNodeAdminMethod
|
||||
}
|
||||
}
|
||||
|
||||
var prmInvoke client.InvokePrm
|
||||
|
||||
prmInvoke.SetMethod(method)
|
||||
prmInvoke.SetArgs(args...)
|
||||
|
||||
err := x.client.Invoke(prmInvoke)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(ManageAdminsPrm), nil
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Client represents Subnet contract client.
|
||||
//
|
||||
// Client should be preliminary initialized (see Init method).
|
||||
type Client struct {
|
||||
client *client.StaticClient
|
||||
}
|
||||
|
||||
// InitPrm groups parameters of Client's initialization.
|
||||
type InitPrm struct {
|
||||
base *client.Client
|
||||
|
||||
addr util.Uint160
|
||||
|
||||
modeSet bool
|
||||
mode Mode
|
||||
}
|
||||
|
||||
const (
|
||||
deleteMethod = "delete"
|
||||
getMethod = "get"
|
||||
putMethod = "put"
|
||||
|
||||
removeClientAdminMethod = "removeClientAdmin"
|
||||
addClientAdminMethod = "addClientAdmin"
|
||||
|
||||
userAllowedMethod = "userAllowed"
|
||||
removeUserMethod = "removeUser"
|
||||
addUserMethod = "addUser"
|
||||
|
||||
removeNodeAdminMethod = "removeNodeAdmin"
|
||||
addNodeAdminMethod = "addNodeAdmin"
|
||||
nodeAllowedMethod = "nodeAllowed"
|
||||
removeNodeMethod = "removeNode"
|
||||
addNodeMethod = "addNode"
|
||||
)
|
||||
|
||||
// SetBaseClient sets basic morph client.
|
||||
func (x *InitPrm) SetBaseClient(base *client.Client) {
|
||||
x.base = base
|
||||
}
|
||||
|
||||
// SetContractAddress sets address of Subnet contract in FrostFS sidechain.
|
||||
func (x *InitPrm) SetContractAddress(addr util.Uint160) {
|
||||
x.addr = addr
|
||||
}
|
||||
|
||||
// Mode regulates client work mode.
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
_ Mode = iota
|
||||
|
||||
// NonNotary makes client to work in non-notary environment.
|
||||
NonNotary
|
||||
|
||||
// NotaryAlphabet makes client to use its internal key for signing the notary requests.
|
||||
NotaryAlphabet
|
||||
|
||||
// NotaryNonAlphabet makes client to not use its internal key for signing the notary requests.
|
||||
NotaryNonAlphabet
|
||||
)
|
||||
|
||||
// SetMode makes client to work with non-notary sidechain.
|
||||
// By default, NonNotary is used.
|
||||
func (x *InitPrm) SetMode(mode Mode) {
|
||||
x.modeSet = true
|
||||
x.mode = mode
|
||||
}
|
||||
|
||||
// Init initializes client with specified parameters.
|
||||
//
|
||||
// Base client must be set.
|
||||
func (x *Client) Init(prm InitPrm) error {
|
||||
if prm.base == nil {
|
||||
panic("missing base morph client")
|
||||
}
|
||||
|
||||
if !prm.modeSet {
|
||||
prm.mode = NonNotary
|
||||
}
|
||||
|
||||
var opts []client.StaticClientOption
|
||||
|
||||
switch prm.mode {
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid work mode %d", prm.mode))
|
||||
case NonNotary:
|
||||
case NotaryNonAlphabet:
|
||||
opts = []client.StaticClientOption{client.TryNotary()}
|
||||
case NotaryAlphabet:
|
||||
opts = []client.StaticClientOption{client.TryNotary(), client.AsAlphabet()}
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
x.client, err = client.NewStatic(prm.base, prm.addr, 0, opts...)
|
||||
|
||||
return err
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
)
|
||||
|
||||
// UserAllowedPrm groups parameters of UserAllowed method of Subnet contract.
|
||||
type UserAllowedPrm struct {
|
||||
args [2]any
|
||||
}
|
||||
|
||||
// SetID sets identifier of the subnet in a binary FrostFS API protocol format.
|
||||
func (x *UserAllowedPrm) SetID(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// SetClient sets owner ID of the client that is being checked in a binary FrostFS API protocol format.
|
||||
func (x *UserAllowedPrm) SetClient(id []byte) {
|
||||
x.args[1] = id
|
||||
}
|
||||
|
||||
// UserAllowedRes groups the resulting values of UserAllowed method of Subnet contract.
|
||||
type UserAllowedRes struct {
|
||||
result bool
|
||||
}
|
||||
|
||||
// Allowed returns true iff the client is allowed to create containers in the subnet.
|
||||
func (x UserAllowedRes) Allowed() bool {
|
||||
return x.result
|
||||
}
|
||||
|
||||
// UserAllowed checks if the user has access to the subnetwork.
|
||||
func (x *Client) UserAllowed(prm UserAllowedPrm) (*UserAllowedRes, error) {
|
||||
args := client.TestInvokePrm{}
|
||||
|
||||
args.SetMethod(userAllowedMethod)
|
||||
args.SetArgs(prm.args[:]...)
|
||||
|
||||
res, err := x.client.TestInvoke(args)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not make test invoke: %w", err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return nil, errEmptyResponse
|
||||
}
|
||||
|
||||
result, err := client.BoolFromStackItem(res[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UserAllowedRes{
|
||||
result: result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ManageClientsPrm groups parameters of client management in Subnet contract.
|
||||
//
|
||||
// Zero value adds subnet client. Subnet, group and client ID must be specified via setters.
|
||||
type ManageClientsPrm struct {
|
||||
// remove or add client
|
||||
rm bool
|
||||
|
||||
args [3]any
|
||||
}
|
||||
|
||||
// SetRemove marks client to be removed. By default, client is added.
|
||||
func (x *ManageClientsPrm) SetRemove() {
|
||||
x.rm = true
|
||||
}
|
||||
|
||||
// SetSubnet sets identifier of the subnet in a binary FrostFS API protocol format.
|
||||
func (x *ManageClientsPrm) SetSubnet(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// SetGroup sets identifier of the client group in a binary FrostFS API protocol format.
|
||||
func (x *ManageClientsPrm) SetGroup(id []byte) {
|
||||
x.args[1] = id
|
||||
}
|
||||
|
||||
// SetClient sets client's user ID in a binary FrostFS API protocol format.
|
||||
func (x *ManageClientsPrm) SetClient(id []byte) {
|
||||
x.args[2] = id
|
||||
}
|
||||
|
||||
// ManageClientsRes groups the resulting values of client management methods of Subnet contract.
|
||||
type ManageClientsRes struct{}
|
||||
|
||||
// ManageClients manages client list of the FrostFS subnet through Subnet contract calls.
|
||||
func (x Client) ManageClients(prm ManageClientsPrm) (*ManageClientsRes, error) {
|
||||
var method string
|
||||
|
||||
if prm.rm {
|
||||
method = removeUserMethod
|
||||
} else {
|
||||
method = addUserMethod
|
||||
}
|
||||
|
||||
var prmInvoke client.InvokePrm
|
||||
|
||||
prmInvoke.SetMethod(method)
|
||||
prmInvoke.SetArgs(prm.args[:]...)
|
||||
|
||||
err := x.client.Invoke(prmInvoke)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(ManageClientsRes), nil
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// DeletePrm groups parameters of Delete method of Subnet contract.
|
||||
type DeletePrm struct {
|
||||
cliPrm client.InvokePrm
|
||||
|
||||
args [1]any
|
||||
}
|
||||
|
||||
// SetTxHash sets hash of the transaction which spawned the notification.
|
||||
// Ignore this parameter for new requests.
|
||||
func (x *DeletePrm) SetTxHash(hash util.Uint256) {
|
||||
x.cliPrm.SetHash(hash)
|
||||
}
|
||||
|
||||
// SetID sets identifier of the subnet to be removed in a binary FrostFS API protocol format.
|
||||
func (x *DeletePrm) SetID(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// DeleteRes groups the resulting values of Delete method of Subnet contract.
|
||||
type DeleteRes struct{}
|
||||
|
||||
// Delete removes subnet though the call of the corresponding method of the Subnet contract.
|
||||
func (x Client) Delete(prm DeletePrm) (*DeleteRes, error) {
|
||||
prm.cliPrm.SetMethod(deleteMethod)
|
||||
prm.cliPrm.SetArgs(prm.args[:]...)
|
||||
|
||||
err := x.client.Invoke(prm.cliPrm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(DeleteRes), nil
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
)
|
||||
|
||||
// GetPrm groups parameters of Get method of Subnet contract.
|
||||
type GetPrm struct {
|
||||
args [1]any
|
||||
}
|
||||
|
||||
// SetID sets identifier of the subnet to be read in a binary FrostFS API protocol format.
|
||||
func (x *GetPrm) SetID(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// GetRes groups the resulting values of Get method of Subnet contract.
|
||||
type GetRes struct {
|
||||
info []byte
|
||||
}
|
||||
|
||||
// Info returns information about the subnet in a binary format of FrostFS API protocol.
|
||||
func (x GetRes) Info() []byte {
|
||||
return x.info
|
||||
}
|
||||
|
||||
var errEmptyResponse = errors.New("empty response")
|
||||
|
||||
// Get reads the subnet through the call of the corresponding method of the Subnet contract.
|
||||
func (x *Client) Get(prm GetPrm) (*GetRes, error) {
|
||||
var prmGet client.TestInvokePrm
|
||||
|
||||
prmGet.SetMethod(getMethod)
|
||||
prmGet.SetArgs(prm.args[:]...)
|
||||
|
||||
res, err := x.client.TestInvoke(prmGet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return nil, errEmptyResponse
|
||||
}
|
||||
|
||||
data, err := client.BytesFromStackItem(res[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &GetRes{
|
||||
info: data,
|
||||
}, nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
)
|
||||
|
||||
// NodeAllowedPrm groups parameters of NodeAllowed method of Subnet contract.
|
||||
type NodeAllowedPrm struct {
|
||||
cliPrm client.TestInvokePrm
|
||||
|
||||
args [2]any
|
||||
}
|
||||
|
||||
// SetID sets identifier of the subnet of the node in a binary FrostFS API protocol format.
|
||||
func (x *NodeAllowedPrm) SetID(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// SetNode sets public key of the node that is being checked.
|
||||
func (x *NodeAllowedPrm) SetNode(id []byte) {
|
||||
x.args[1] = id
|
||||
}
|
||||
|
||||
// NodeAllowedRes groups the resulting values of NodeAllowed method of Subnet contract.
|
||||
type NodeAllowedRes struct {
|
||||
result bool
|
||||
}
|
||||
|
||||
// Allowed returns true iff the node is allowed to enter the subnet.
|
||||
func (x NodeAllowedRes) Allowed() bool {
|
||||
return x.result
|
||||
}
|
||||
|
||||
// NodeAllowed checks if the node is included in the subnetwork.
|
||||
func (x *Client) NodeAllowed(prm NodeAllowedPrm) (*NodeAllowedRes, error) {
|
||||
prm.cliPrm.SetMethod(nodeAllowedMethod)
|
||||
prm.cliPrm.SetArgs(prm.args[:]...)
|
||||
|
||||
res, err := x.client.TestInvoke(prm.cliPrm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not make test invoke: %w", err)
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return nil, errEmptyResponse
|
||||
}
|
||||
|
||||
result, err := client.BoolFromStackItem(res[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &NodeAllowedRes{
|
||||
result: result,
|
||||
}, nil
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
|
||||
// ManageNodesPrm groups parameters of node management in Subnet contract.
|
||||
//
|
||||
// Zero value adds node to subnet. Subnet and node IDs must be specified via setters.
|
||||
type ManageNodesPrm struct {
|
||||
// remove or add node
|
||||
rm bool
|
||||
|
||||
args [2]any
|
||||
}
|
||||
|
||||
// SetRemove marks node to be removed. By default, node is added.
|
||||
func (x *ManageNodesPrm) SetRemove() {
|
||||
x.rm = true
|
||||
}
|
||||
|
||||
// SetSubnet sets identifier of the subnet in a binary NeoFS API protocol format.
|
||||
func (x *ManageNodesPrm) SetSubnet(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// SetNode sets node's public key in a binary format.
|
||||
func (x *ManageNodesPrm) SetNode(id []byte) {
|
||||
x.args[1] = id
|
||||
}
|
||||
|
||||
// ManageNodesRes groups the resulting values of node management methods of Subnet contract.
|
||||
type ManageNodesRes struct{}
|
||||
|
||||
// ManageNodes manages node list of the NeoFS subnet through Subnet contract calls.
|
||||
func (x Client) ManageNodes(prm ManageNodesPrm) (*ManageNodesRes, error) {
|
||||
var method string
|
||||
|
||||
if prm.rm {
|
||||
method = removeNodeMethod
|
||||
} else {
|
||||
method = addNodeMethod
|
||||
}
|
||||
|
||||
var prmInvoke client.InvokePrm
|
||||
|
||||
prmInvoke.SetMethod(method)
|
||||
prmInvoke.SetArgs(prm.args[:]...)
|
||||
|
||||
err := x.client.Invoke(prmInvoke)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(ManageNodesRes), nil
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package morphsubnet
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// PutPrm groups parameters of Put method of Subnet contract.
|
||||
type PutPrm struct {
|
||||
cliPrm client.InvokePrm
|
||||
|
||||
args [3]any
|
||||
}
|
||||
|
||||
// SetTxHash sets hash of the transaction which spawned the notification.
|
||||
// Ignore this parameter for new requests.
|
||||
func (x *PutPrm) SetTxHash(hash util.Uint256) {
|
||||
x.cliPrm.SetHash(hash)
|
||||
}
|
||||
|
||||
// SetID sets identifier of the created subnet in a binary FrostFS API protocol format.
|
||||
func (x *PutPrm) SetID(id []byte) {
|
||||
x.args[0] = id
|
||||
}
|
||||
|
||||
// SetOwner sets identifier of the subnet owner in a binary FrostFS API protocol format.
|
||||
func (x *PutPrm) SetOwner(id []byte) {
|
||||
x.args[1] = id
|
||||
}
|
||||
|
||||
// SetInfo sets information about the created subnet in a binary FrostFS API protocol format.
|
||||
func (x *PutPrm) SetInfo(id []byte) {
|
||||
x.args[2] = id
|
||||
}
|
||||
|
||||
// PutRes groups the resulting values of Put method of Subnet contract.
|
||||
type PutRes struct{}
|
||||
|
||||
// Put creates subnet though the call of the corresponding method of the Subnet contract.
|
||||
func (x Client) Put(prm PutPrm) (*PutRes, error) {
|
||||
prm.cliPrm.SetMethod(putMethod)
|
||||
prm.cliPrm.SetArgs(prm.args[:]...)
|
||||
|
||||
err := x.client.Invoke(prm.cliPrm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return new(PutRes), nil
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Delete structures information about the notification generated by Delete method of Subnet contract.
|
||||
type Delete struct {
|
||||
txHash util.Uint256
|
||||
|
||||
id []byte
|
||||
}
|
||||
|
||||
// MorphEvent implements Neo:Morph Event interface.
|
||||
func (Delete) MorphEvent() {}
|
||||
|
||||
// ID returns identifier of the removed subnet in a binary format of NeoFS API protocol.
|
||||
func (x Delete) ID() []byte {
|
||||
return x.id
|
||||
}
|
||||
|
||||
// TxHash returns hash of the transaction which thrown the notification event.
|
||||
// Makes sense only in notary environments.
|
||||
func (x Delete) TxHash() util.Uint256 {
|
||||
return x.txHash
|
||||
}
|
||||
|
||||
// ParseDelete parses the notification about the removal of a subnet which has been thrown
|
||||
// by the appropriate method of the Subnet contract.
|
||||
//
|
||||
// Resulting event is of Delete type.
|
||||
func ParseDelete(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||
var (
|
||||
ev Delete
|
||||
err error
|
||||
)
|
||||
|
||||
items, err := event.ParseStackArray(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse stack array: %w", err)
|
||||
}
|
||||
|
||||
const itemNumDelete = 1
|
||||
|
||||
if ln := len(items); ln != itemNumDelete {
|
||||
return nil, event.WrongNumberOfParameters(itemNumDelete, ln)
|
||||
}
|
||||
|
||||
// parse ID
|
||||
ev.id, err = client.BytesFromStackItem(items[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("id item: %w", err)
|
||||
}
|
||||
|
||||
ev.txHash = e.Container
|
||||
|
||||
return ev, nil
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package subnetevents_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
subnetevents "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseDelete(t *testing.T) {
|
||||
id := []byte("id")
|
||||
|
||||
t.Run("wrong number of items", func(t *testing.T) {
|
||||
prms := []stackitem.Item{
|
||||
stackitem.NewByteArray(nil),
|
||||
stackitem.NewByteArray(nil),
|
||||
}
|
||||
|
||||
_, err := subnetevents.ParseDelete(createNotifyEventFromItems(prms))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong id item", func(t *testing.T) {
|
||||
_, err := subnetevents.ParseDelete(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("correct behavior", func(t *testing.T) {
|
||||
ev, err := subnetevents.ParseDelete(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(id),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
|
||||
v := ev.(subnetevents.Delete)
|
||||
|
||||
require.Equal(t, id, v.ID())
|
||||
})
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Put structures information about the notification generated by Put method of Subnet contract.
|
||||
type Put struct {
|
||||
notaryRequest *payload.P2PNotaryRequest
|
||||
|
||||
txHash util.Uint256
|
||||
|
||||
id []byte
|
||||
|
||||
owner []byte
|
||||
|
||||
info []byte
|
||||
}
|
||||
|
||||
// MorphEvent implements Neo:Morph Event interface.
|
||||
func (Put) MorphEvent() {}
|
||||
|
||||
// ID returns identifier of the creating subnet in a binary format of FrostFS API protocol.
|
||||
func (x Put) ID() []byte {
|
||||
return x.id
|
||||
}
|
||||
|
||||
// Owner returns subnet owner's public key in a binary format.
|
||||
func (x Put) Owner() []byte {
|
||||
return x.owner
|
||||
}
|
||||
|
||||
// Info returns information about the subnet in a binary format of FrostFS API protocol.
|
||||
func (x Put) Info() []byte {
|
||||
return x.info
|
||||
}
|
||||
|
||||
// TxHash returns hash of the transaction which thrown the notification event.
|
||||
// Makes sense only in notary environments.
|
||||
func (x Put) TxHash() util.Uint256 {
|
||||
return x.txHash
|
||||
}
|
||||
|
||||
// NotaryMainTx returns main transaction of the request in the Notary service.
|
||||
// Returns nil in non-notary environments.
|
||||
func (x Put) NotaryMainTx() *transaction.Transaction {
|
||||
if x.notaryRequest != nil {
|
||||
return x.notaryRequest.MainTransaction
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// number of items in notification about subnet creation.
|
||||
const itemNumPut = 3
|
||||
|
||||
// ParsePut parses the notification about the creation of a subnet which has been thrown
|
||||
// by the appropriate method of the subnet contract.
|
||||
//
|
||||
// Resulting event is of Put type.
|
||||
func ParsePut(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||
var (
|
||||
put Put
|
||||
err error
|
||||
)
|
||||
|
||||
items, err := event.ParseStackArray(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse stack array: %w", err)
|
||||
}
|
||||
|
||||
if ln := len(items); ln != itemNumPut {
|
||||
return nil, event.WrongNumberOfParameters(itemNumPut, ln)
|
||||
}
|
||||
|
||||
// parse ID
|
||||
put.id, err = client.BytesFromStackItem(items[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("id item: %w", err)
|
||||
}
|
||||
|
||||
// parse owner
|
||||
put.owner, err = client.BytesFromStackItem(items[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("owner item: %w", err)
|
||||
}
|
||||
|
||||
// parse info about subnet
|
||||
put.info, err = client.BytesFromStackItem(items[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("info item: %w", err)
|
||||
}
|
||||
|
||||
put.txHash = e.Container
|
||||
|
||||
return put, nil
|
||||
}
|
||||
|
||||
// ParseNotaryPut parses the notary notification about the creation of a subnet which has been
|
||||
// thrown by the appropriate method of the subnet contract.
|
||||
//
|
||||
// Resulting event is of Put type.
|
||||
func ParseNotaryPut(e event.NotaryEvent) (event.Event, error) {
|
||||
var put Put
|
||||
|
||||
put.notaryRequest = e.Raw()
|
||||
if put.notaryRequest == nil {
|
||||
panic(fmt.Sprintf("nil %T in notary environment", put.notaryRequest))
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
|
||||
prms = e.Params()
|
||||
)
|
||||
|
||||
if ln := len(prms); ln != itemNumPut {
|
||||
return nil, event.WrongNumberOfParameters(itemNumPut, ln)
|
||||
}
|
||||
|
||||
// parse info about subnet
|
||||
put.info, err = event.BytesFromOpcode(prms[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("info param: %w", err)
|
||||
}
|
||||
|
||||
// parse owner
|
||||
put.owner, err = event.BytesFromOpcode(prms[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creator param: %w", err)
|
||||
}
|
||||
|
||||
// parse ID
|
||||
put.id, err = event.BytesFromOpcode(prms[2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("id param: %w", err)
|
||||
}
|
||||
|
||||
return put, nil
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package subnetevents_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
subnetevents "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParsePut(t *testing.T) {
|
||||
var (
|
||||
id = []byte("id")
|
||||
owner = []byte("owner")
|
||||
info = []byte("info")
|
||||
)
|
||||
|
||||
t.Run("wrong number of items", func(t *testing.T) {
|
||||
prms := []stackitem.Item{
|
||||
stackitem.NewByteArray(nil),
|
||||
stackitem.NewByteArray(nil),
|
||||
}
|
||||
|
||||
_, err := subnetevents.ParsePut(createNotifyEventFromItems(prms))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong id item", func(t *testing.T) {
|
||||
_, err := subnetevents.ParsePut(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong owner item", func(t *testing.T) {
|
||||
_, err := subnetevents.ParsePut(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(id),
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong info item", func(t *testing.T) {
|
||||
_, err := subnetevents.ParsePut(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(id),
|
||||
stackitem.NewByteArray(owner),
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("correct behavior", func(t *testing.T) {
|
||||
ev, err := subnetevents.ParsePut(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(id),
|
||||
stackitem.NewByteArray(owner),
|
||||
stackitem.NewByteArray(info),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
|
||||
v := ev.(subnetevents.Put)
|
||||
|
||||
require.Equal(t, id, v.ID())
|
||||
require.Equal(t, owner, v.Owner())
|
||||
require.Equal(t, info, v.Info())
|
||||
})
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package subnetevents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// RemoveNode structure of subnet.RemoveNode notification from morph chain.
|
||||
type RemoveNode struct {
|
||||
subnetID []byte
|
||||
nodeKey []byte
|
||||
|
||||
// txHash is used in notary environmental
|
||||
// for calculating unique but same for
|
||||
// all notification receivers values.
|
||||
txHash util.Uint256
|
||||
}
|
||||
|
||||
// MorphEvent implements Neo:Morph Event interface.
|
||||
func (RemoveNode) MorphEvent() {}
|
||||
|
||||
// SubnetworkID returns a marshalled subnetID structure, defined in API.
|
||||
func (rn RemoveNode) SubnetworkID() []byte { return rn.subnetID }
|
||||
|
||||
// Node is public key of the nodeKey that is being deleted.
|
||||
func (rn RemoveNode) Node() []byte { return rn.nodeKey }
|
||||
|
||||
// TxHash returns hash of the TX with RemoveNode
|
||||
// notification.
|
||||
func (rn RemoveNode) TxHash() util.Uint256 { return rn.txHash }
|
||||
|
||||
const expectedItemNumRemoveNode = 2
|
||||
|
||||
// ParseRemoveNode parses notification into subnet event structure.
|
||||
//
|
||||
// Expects 2 stack items.
|
||||
func ParseRemoveNode(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||
var (
|
||||
ev RemoveNode
|
||||
err error
|
||||
)
|
||||
|
||||
params, err := event.ParseStackArray(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
||||
}
|
||||
|
||||
if ln := len(params); ln != expectedItemNumRemoveNode {
|
||||
return nil, event.WrongNumberOfParameters(expectedItemNumRemoveNode, ln)
|
||||
}
|
||||
|
||||
ev.subnetID, err = client.BytesFromStackItem(params[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get raw subnetID: %w", err)
|
||||
}
|
||||
|
||||
ev.nodeKey, err = client.BytesFromStackItem(params[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get raw public key of the node: %w", err)
|
||||
}
|
||||
|
||||
ev.txHash = e.Container
|
||||
|
||||
return ev, nil
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package subnetevents_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/subnet"
|
||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseRemoveNode(t *testing.T) {
|
||||
t.Run("wrong number of arguments", func(t *testing.T) {
|
||||
_, err := ParseRemoveNode(createNotifyEventFromItems([]stackitem.Item{}))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid item type", func(t *testing.T) {
|
||||
args := []stackitem.Item{stackitem.NewMap(), stackitem.Make(123)}
|
||||
_, err := ParseRemoveNode(createNotifyEventFromItems(args))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
subnetID := subnetid.ID{}
|
||||
subnetID.SetNumeric(123)
|
||||
|
||||
rawSubnetID := subnetID.Marshal()
|
||||
|
||||
priv, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
pub := priv.PublicKey()
|
||||
|
||||
t.Run("good", func(t *testing.T) {
|
||||
args := []stackitem.Item{stackitem.NewByteArray(rawSubnetID), stackitem.Make(pub.Bytes())}
|
||||
|
||||
e, err := ParseRemoveNode(createNotifyEventFromItems(args))
|
||||
require.NoError(t, err)
|
||||
|
||||
gotRaw := e.(RemoveNode).SubnetworkID()
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, rawSubnetID, gotRaw)
|
||||
require.Equal(t, pub.Bytes(), e.(RemoveNode).Node())
|
||||
})
|
||||
}
|
||||
|
||||
func createNotifyEventFromItems(items []stackitem.Item) *state.ContainedNotificationEvent {
|
||||
return &state.ContainedNotificationEvent{
|
||||
NotificationEvent: state.NotificationEvent{
|
||||
Item: stackitem.NewArray(items),
|
||||
},
|
||||
}
|
||||
}
|
BIN
pkg/services/control/ir/service.pb.go
generated
BIN
pkg/services/control/ir/service.pb.go
generated
Binary file not shown.
BIN
pkg/services/control/ir/service_grpc.pb.go
generated
BIN
pkg/services/control/ir/service_grpc.pb.go
generated
Binary file not shown.
BIN
pkg/services/control/ir/types.pb.go
generated
BIN
pkg/services/control/ir/types.pb.go
generated
Binary file not shown.
BIN
pkg/services/control/types.pb.go
generated
BIN
pkg/services/control/types.pb.go
generated
Binary file not shown.
|
@ -54,9 +54,6 @@ message NodeInfo {
|
|||
// attributes it's a string presenting floating point number with comma or
|
||||
// point delimiter for decimal part. In the Network Map it will be saved as
|
||||
// 64-bit unsigned integer representing number of minimal token fractions.
|
||||
// * Subnet \
|
||||
// String ID of Node's storage subnet. There can be only one subnet served
|
||||
// by the Storage Node.
|
||||
// * Locode \
|
||||
// Node's geographic location in
|
||||
// [UN/LOCODE](https://www.unece.org/cefact/codesfortrade/codes_index.html)
|
||||
|
|
BIN
pkg/services/tree/service.pb.go
generated
BIN
pkg/services/tree/service.pb.go
generated
Binary file not shown.
BIN
pkg/services/tree/service_grpc.pb.go
generated
BIN
pkg/services/tree/service_grpc.pb.go
generated
Binary file not shown.
BIN
pkg/services/tree/types.pb.go
generated
BIN
pkg/services/tree/types.pb.go
generated
Binary file not shown.
Loading…
Reference in a new issue