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.frostfs", "10")
|
||||||
cfg.SetDefault("workers.container", "10")
|
cfg.SetDefault("workers.container", "10")
|
||||||
cfg.SetDefault("workers.alphabet", "10")
|
cfg.SetDefault("workers.alphabet", "10")
|
||||||
cfg.SetDefault("workers.subnet", "10")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTimersDefaults(cfg *viper.Viper) {
|
func setTimersDefaults(cfg *viper.Viper) {
|
||||||
|
@ -163,7 +162,6 @@ func setContractsDefaults(cfg *viper.Viper) {
|
||||||
cfg.SetDefault("contracts.audit", "")
|
cfg.SetDefault("contracts.audit", "")
|
||||||
cfg.SetDefault("contracts.proxy", "")
|
cfg.SetDefault("contracts.proxy", "")
|
||||||
cfg.SetDefault("contracts.processing", "")
|
cfg.SetDefault("contracts.processing", "")
|
||||||
cfg.SetDefault("contracts.subnet", "")
|
|
||||||
cfg.SetDefault("contracts.proxy", "")
|
cfg.SetDefault("contracts.proxy", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,6 @@ FROSTFS_IR_WORKERS_BALANCE=10
|
||||||
FROSTFS_IR_WORKERS_CONTAINER=10
|
FROSTFS_IR_WORKERS_CONTAINER=10
|
||||||
FROSTFS_IR_WORKERS_NEOFS=10
|
FROSTFS_IR_WORKERS_NEOFS=10
|
||||||
FROSTFS_IR_WORKERS_NETMAP=10
|
FROSTFS_IR_WORKERS_NETMAP=10
|
||||||
FROSTFS_IR_WORKERS_SUBNET=10
|
|
||||||
|
|
||||||
FROSTFS_IR_AUDIT_TIMEOUT_GET=5s
|
FROSTFS_IR_AUDIT_TIMEOUT_GET=5s
|
||||||
FROSTFS_IR_AUDIT_TIMEOUT_HEAD=5s
|
FROSTFS_IR_AUDIT_TIMEOUT_HEAD=5s
|
||||||
|
@ -74,7 +73,6 @@ FROSTFS_IR_CONTRACTS_CONTAINER=ed4a7a66fe3f9bfe50f214b49be8f215a3c886b6
|
||||||
FROSTFS_IR_CONTRACTS_NEOFSID=9f5866decbc751a099e74c7c7bc89f609201755a
|
FROSTFS_IR_CONTRACTS_NEOFSID=9f5866decbc751a099e74c7c7bc89f609201755a
|
||||||
FROSTFS_IR_CONTRACTS_NETMAP=83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
FROSTFS_IR_CONTRACTS_NETMAP=83c600c81d47a1b1b7cf58eb49ae7ee7240dc742
|
||||||
FROSTFS_IR_CONTRACTS_PROXY=abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
FROSTFS_IR_CONTRACTS_PROXY=abc8794bb40a21f2db5f21ae62741eb46c8cad1c
|
||||||
FROSTFS_IR_CONTRACTS_SUBNET=e9266864d3c562c6e17f2bb9cb1392aaa293d93a
|
|
||||||
FROSTFS_IR_CONTRACTS_ALPHABET_AMOUNT=7
|
FROSTFS_IR_CONTRACTS_ALPHABET_AMOUNT=7
|
||||||
FROSTFS_IR_CONTRACTS_ALPHABET_AZ=c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
FROSTFS_IR_CONTRACTS_ALPHABET_AZ=c1d211fceeb4b1dc76b8e4054d11fdf887e418ea
|
||||||
FROSTFS_IR_CONTRACTS_ALPHABET_BUKY=e2ba789320899658b100f331bdebb74474757920
|
FROSTFS_IR_CONTRACTS_ALPHABET_BUKY=e2ba789320899658b100f331bdebb74474757920
|
||||||
|
|
|
@ -83,7 +83,6 @@ workers:
|
||||||
container: 10 # Number of workers to process events from container contract in parallel
|
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
|
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
|
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:
|
audit:
|
||||||
timeout:
|
timeout:
|
||||||
|
@ -116,7 +115,6 @@ contracts:
|
||||||
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a # Optional: override address of frostfsid contract in sidechain
|
frostfsid: 9f5866decbc751a099e74c7c7bc89f609201755a # Optional: override address of frostfsid contract in sidechain
|
||||||
netmap: 83c600c81d47a1b1b7cf58eb49ae7ee7240dc742 # Optional: override address of netmap 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
|
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:
|
alphabet:
|
||||||
amount: 7 # Optional: override amount of alphabet contracts
|
amount: 7 # Optional: override amount of alphabet contracts
|
||||||
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea # Optional: override address of az alphabet contract in sidechain
|
az: c1d211fceeb4b1dc76b8e4054d11fdf887e418ea # Optional: override address of az alphabet contract in sidechain
|
||||||
|
|
|
@ -18,7 +18,6 @@ type contracts struct {
|
||||||
audit util.Uint160 // in morph
|
audit util.Uint160 // in morph
|
||||||
proxy util.Uint160 // in morph
|
proxy util.Uint160 // in morph
|
||||||
processing util.Uint160 // in mainnet
|
processing util.Uint160 // in mainnet
|
||||||
subnet util.Uint160 // in morph
|
|
||||||
frostfsID util.Uint160 // in morph
|
frostfsID util.Uint160 // in morph
|
||||||
|
|
||||||
alphabet alphabetContracts // 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.balance", client.NNSBalanceContractName, &result.balance},
|
||||||
{"contracts.container", client.NNSContainerContractName, &result.container},
|
{"contracts.container", client.NNSContainerContractName, &result.container},
|
||||||
{"contracts.audit", client.NNSAuditContractName, &result.audit},
|
{"contracts.audit", client.NNSAuditContractName, &result.audit},
|
||||||
{"contracts.subnet", client.NNSSubnetworkContractName, &result.subnet},
|
|
||||||
{"contracts.frostfsid", client.NNSFrostFSIDContractName, &result.frostfsID},
|
{"contracts.frostfsid", client.NNSFrostFSIDContractName, &result.frostfsID},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import (
|
||||||
nodevalidator "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/netmap/nodevalidation"
|
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"
|
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"
|
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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement"
|
||||||
auditSettlement "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement/audit"
|
auditSettlement "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/processors/settlement/audit"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/metrics"
|
||||||
|
@ -28,7 +27,6 @@ import (
|
||||||
frostfsClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
frostfsClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
audittask "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/audit/taskmanager"
|
audittask "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/audit/taskmanager"
|
||||||
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
control "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/control/ir"
|
||||||
|
@ -46,7 +44,6 @@ import (
|
||||||
func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
||||||
cnrClient *container.Client,
|
cnrClient *container.Client,
|
||||||
alphaSync event.Handler,
|
alphaSync event.Handler,
|
||||||
subnetClient *morphsubnet.Client,
|
|
||||||
auditProcessor *audit.Processor,
|
auditProcessor *audit.Processor,
|
||||||
settlementProcessor *settlement.Processor) error {
|
settlementProcessor *settlement.Processor) error {
|
||||||
locodeValidator, err := s.newLocodeValidator(cfg)
|
locodeValidator, err := s.newLocodeValidator(cfg)
|
||||||
|
@ -54,11 +51,6 @@ func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
subnetValidator, err := subnetvalidator.New(
|
|
||||||
subnetvalidator.Prm{
|
|
||||||
SubnetClient: subnetClient,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -94,10 +86,8 @@ func (s *Server) initNetmapProcessor(cfg *viper.Viper,
|
||||||
&netMapCandidateStateValidator,
|
&netMapCandidateStateValidator,
|
||||||
addrvalidator.New(),
|
addrvalidator.New(),
|
||||||
locodeValidator,
|
locodeValidator,
|
||||||
subnetValidator,
|
|
||||||
),
|
),
|
||||||
NotaryDisabled: s.sideNotaryConfig.disabled,
|
NotaryDisabled: s.sideNotaryConfig.disabled,
|
||||||
SubnetContract: &s.contracts.subnet,
|
|
||||||
|
|
||||||
NodeStateSettings: netSettings,
|
NodeStateSettings: netSettings,
|
||||||
})
|
})
|
||||||
|
@ -349,27 +339,6 @@ func (s *Server) initTimers(cfg *viper.Viper, processors *serverProcessors, morp
|
||||||
s.addBlockTimer(emissionTimer)
|
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) {
|
func (s *Server) initAlphabetProcessor(cfg *viper.Viper) (*alphabet.Processor, error) {
|
||||||
parsedWallets, err := parseWalletAddressesFromStrings(cfg.GetStringSlice("emit.extra_wallets"))
|
parsedWallets, err := parseWalletAddressesFromStrings(cfg.GetStringSlice("emit.extra_wallets"))
|
||||||
if err != nil {
|
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,
|
func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.Client,
|
||||||
frostfsIDClient *frostfsid.Client, subnetClient *morphsubnet.Client) error {
|
frostfsIDClient *frostfsid.Client) error {
|
||||||
// container processor
|
// container processor
|
||||||
containerProcessor, err := cont.New(&cont.Params{
|
containerProcessor, err := cont.New(&cont.Params{
|
||||||
Log: s.log,
|
Log: s.log,
|
||||||
|
@ -410,7 +379,6 @@ func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.C
|
||||||
FrostFSIDClient: frostfsIDClient,
|
FrostFSIDClient: frostfsIDClient,
|
||||||
NetworkState: s.netmapClient,
|
NetworkState: s.netmapClient,
|
||||||
NotaryDisabled: s.sideNotaryConfig.disabled,
|
NotaryDisabled: s.sideNotaryConfig.disabled,
|
||||||
SubnetClient: subnetClient,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -518,7 +486,6 @@ type serverMorphClients struct {
|
||||||
CnrClient *container.Client
|
CnrClient *container.Client
|
||||||
FrostFSIDClient *frostfsid.Client
|
FrostFSIDClient *frostfsid.Client
|
||||||
FrostFSClient *frostfsClient.Client
|
FrostFSClient *frostfsClient.Client
|
||||||
MorphSubnetClient *morphsubnet.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
||||||
|
@ -574,11 +541,6 @@ func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result.MorphSubnetClient, err = s.createMorphSubnetClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,12 +586,12 @@ func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClien
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.initContainerProcessor(cfg, morphClients.CnrClient, morphClients.FrostFSIDClient, morphClients.MorphSubnetClient)
|
err = s.initContainerProcessor(cfg, morphClients.CnrClient, morphClients.FrostFSIDClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,8 +100,6 @@ type (
|
||||||
// should report start errors
|
// should report start errors
|
||||||
// to the application.
|
// to the application.
|
||||||
runners []func(chan<- error) error
|
runners []func(chan<- error) error
|
||||||
|
|
||||||
subnetHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chainParams struct {
|
chainParams struct {
|
||||||
|
@ -400,10 +398,6 @@ func New(ctx context.Context, log *logger.Logger, cfg *viper.Viper, errChan chan
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
server.initSubnet(subnetConfig{
|
|
||||||
queueSize: cfg.GetUint32("workers.subnet"),
|
|
||||||
})
|
|
||||||
|
|
||||||
server.initMetrics(cfg)
|
server.initMetrics(cfg)
|
||||||
|
|
||||||
return server, nil
|
return server, nil
|
||||||
|
|
|
@ -5,13 +5,11 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||||
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
containerSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
"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"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -77,12 +75,6 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
||||||
return fmt.Errorf("auth container creation: %w", err)
|
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
|
// check homomorphic hashing setting
|
||||||
err = checkHomomorphicHashing(cp.netState, cnr)
|
err = checkHomomorphicHashing(cp.netState, cnr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -222,29 +214,6 @@ func checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
||||||
return nil
|
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 {
|
func checkHomomorphicHashing(ns NetworkState, cnr containerSDK.Container) error {
|
||||||
netSetting, err := ns.HomomorphicHashDisabled()
|
netSetting, err := ns.HomomorphicHashDisabled()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"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/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
"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"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||||
|
@ -29,7 +28,6 @@ type (
|
||||||
alphabetState AlphabetState
|
alphabetState AlphabetState
|
||||||
cnrClient *container.Client // notary must be enabled
|
cnrClient *container.Client // notary must be enabled
|
||||||
idClient *frostfsid.Client
|
idClient *frostfsid.Client
|
||||||
subnetClient *morphsubnet.Client
|
|
||||||
netState NetworkState
|
netState NetworkState
|
||||||
notaryDisabled bool
|
notaryDisabled bool
|
||||||
}
|
}
|
||||||
|
@ -41,7 +39,6 @@ type (
|
||||||
AlphabetState AlphabetState
|
AlphabetState AlphabetState
|
||||||
ContainerClient *container.Client
|
ContainerClient *container.Client
|
||||||
FrostFSIDClient *frostfsid.Client
|
FrostFSIDClient *frostfsid.Client
|
||||||
SubnetClient *morphsubnet.Client
|
|
||||||
NetworkState NetworkState
|
NetworkState NetworkState
|
||||||
NotaryDisabled bool
|
NotaryDisabled bool
|
||||||
}
|
}
|
||||||
|
@ -85,8 +82,6 @@ func New(p *Params) (*Processor, error) {
|
||||||
return nil, errors.New("ir/container: FrostFS ID client is not set")
|
return nil, errors.New("ir/container: FrostFS ID client is not set")
|
||||||
case p.NetworkState == nil:
|
case p.NetworkState == nil:
|
||||||
return nil, errors.New("ir/container: network state is not set")
|
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))
|
p.Log.Debug(logs.ContainerContainerWorkerPool, zap.Int("size", p.PoolSize))
|
||||||
|
@ -104,7 +99,6 @@ func New(p *Params) (*Processor, error) {
|
||||||
idClient: p.FrostFSIDClient,
|
idClient: p.FrostFSIDClient,
|
||||||
netState: p.NetworkState,
|
netState: p.NetworkState,
|
||||||
notaryDisabled: p.NotaryDisabled,
|
notaryDisabled: p.NotaryDisabled,
|
||||||
subnetClient: p.SubnetClient,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
timerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
timerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/timers"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/netmap"
|
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"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,22 +100,3 @@ func (np *Processor) handleCleanupTick(ev event.Event) {
|
||||||
zap.Int("capacity", np.pool.Cap()))
|
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
|
package netmap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||||
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
netmapclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/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"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
subnetid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/subnet/id"
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,74 +136,3 @@ func (np *Processor) processUpdatePeer(ev netmapEvent.UpdatePeer) {
|
||||||
np.log.Error(logs.NetmapCantInvokeNetmapUpdatePeer, zap.Error(err))
|
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"
|
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"
|
||||||
netmapEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/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-node/pkg/util/logger"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/panjf2000/ants/v2"
|
"github.com/panjf2000/ants/v2"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
@ -65,8 +63,6 @@ type (
|
||||||
netmapClient *nmClient.Client
|
netmapClient *nmClient.Client
|
||||||
containerWrp *container.Client
|
containerWrp *container.Client
|
||||||
|
|
||||||
subnetContract util.Uint160
|
|
||||||
|
|
||||||
netmapSnapshot cleanupTable
|
netmapSnapshot cleanupTable
|
||||||
|
|
||||||
handleNewAudit event.Handler
|
handleNewAudit event.Handler
|
||||||
|
@ -92,7 +88,6 @@ type (
|
||||||
CleanupEnabled bool
|
CleanupEnabled bool
|
||||||
CleanupThreshold uint64 // in epochs
|
CleanupThreshold uint64 // in epochs
|
||||||
ContainerWrapper *container.Client
|
ContainerWrapper *container.Client
|
||||||
SubnetContract *util.Uint160
|
|
||||||
|
|
||||||
HandleAudit event.Handler
|
HandleAudit event.Handler
|
||||||
AuditSettlementsHandler event.Handler
|
AuditSettlementsHandler event.Handler
|
||||||
|
@ -111,7 +106,6 @@ const (
|
||||||
newEpochNotification = "NewEpoch"
|
newEpochNotification = "NewEpoch"
|
||||||
addPeerNotification = "AddPeer"
|
addPeerNotification = "AddPeer"
|
||||||
updatePeerStateNotification = "UpdateState"
|
updatePeerStateNotification = "UpdateState"
|
||||||
removeNodeNotification = "RemoveNode"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// New creates network map contract processor instance.
|
// 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")
|
return nil, errors.New("ir/netmap: container contract wrapper is not set")
|
||||||
case p.NodeValidator == nil:
|
case p.NodeValidator == nil:
|
||||||
return nil, errors.New("ir/netmap: node validator is not set")
|
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:
|
case p.NodeStateSettings == nil:
|
||||||
return nil, errors.New("ir/netmap: node state settings is not set")
|
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,
|
containerWrp: p.ContainerWrapper,
|
||||||
netmapSnapshot: newCleanupTable(p.CleanupEnabled, p.CleanupThreshold),
|
netmapSnapshot: newCleanupTable(p.CleanupEnabled, p.CleanupThreshold),
|
||||||
handleNewAudit: p.HandleAudit,
|
handleNewAudit: p.HandleAudit,
|
||||||
subnetContract: *p.SubnetContract,
|
|
||||||
|
|
||||||
handleAuditSettlements: p.AuditSettlementsHandler,
|
handleAuditSettlements: p.AuditSettlementsHandler,
|
||||||
|
|
||||||
|
@ -182,13 +173,6 @@ func (np *Processor) ListenerNotificationParsers() []event.NotificationParserInf
|
||||||
|
|
||||||
var p event.NotificationParserInfo
|
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())
|
p.SetScriptHash(np.netmapClient.ContractAddress())
|
||||||
|
|
||||||
// new epoch event
|
// new epoch event
|
||||||
|
@ -219,13 +203,6 @@ func (np *Processor) ListenerNotificationHandlers() []event.NotificationHandlerI
|
||||||
|
|
||||||
var i event.NotificationHandlerInfo
|
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())
|
i.SetScriptHash(np.netmapClient.ContractAddress())
|
||||||
|
|
||||||
// new epoch handler
|
// 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"
|
NNSNetmapContractName = "netmap.frostfs"
|
||||||
// NNSProxyContractName is a name of the proxy contract in NNS.
|
// NNSProxyContractName is a name of the proxy contract in NNS.
|
||||||
NNSProxyContractName = "proxy.frostfs"
|
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 is a name for the FrostFS group key record in NNS.
|
||||||
NNSGroupKeyName = "group.frostfs"
|
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
|
// 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
|
// point delimiter for decimal part. In the Network Map it will be saved as
|
||||||
// 64-bit unsigned integer representing number of minimal token fractions.
|
// 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 \
|
// * Locode \
|
||||||
// Node's geographic location in
|
// Node's geographic location in
|
||||||
// [UN/LOCODE](https://www.unece.org/cefact/codesfortrade/codes_index.html)
|
// [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