From 8419294f22992d325254e76f97f753f3d114c0d1 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Mon, 1 Feb 2021 15:29:35 +0300 Subject: [PATCH] [#328] container/load: Implement AnnounceUsedSpace NeoFS API v2 RPC handler Implement processing of AnnounceUsedSpace RPC from NeoFS API v2 method on the app-side according to the following algorithm (except common steps for each RPC): * check if the request sender is presented in container; * check route of the request (compose from signatures); * pass the value to Writer returned by WriterProvider. Signed-off-by: Leonard Lyubich --- cmd/neofs-node/container.go | 123 ++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/cmd/neofs-node/container.go b/cmd/neofs-node/container.go index 49c979bd..17f5bfc3 100644 --- a/cmd/neofs-node/container.go +++ b/cmd/neofs-node/container.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "context" "crypto/ecdsa" "strconv" @@ -8,6 +9,7 @@ import ( apiClient "github.com/nspcc-dev/neofs-api-go/pkg/client" containerSDK "github.com/nspcc-dev/neofs-api-go/pkg/container" "github.com/nspcc-dev/neofs-api-go/pkg/netmap" + containerV2 "github.com/nspcc-dev/neofs-api-go/v2/container" containerGRPC "github.com/nspcc-dev/neofs-api-go/v2/container/grpc" containerCore "github.com/nspcc-dev/neofs-node/pkg/core/container" netmapCore "github.com/nspcc-dev/neofs-node/pkg/core/netmap" @@ -236,3 +238,124 @@ func (d *localStorageLoad) Iterate(f loadcontroller.UsedSpaceFilter, h loadcontr return nil } + +type usedSpaceService struct { + containerV2.Service + + loadWriterProvider loadcontroller.WriterProvider + + loadPlacementBuilder *loadPlacementBuilder + + routeBuilder loadroute.Builder + + cfg *cfg +} + +func (c *cfg) PublicKey() []byte { + ni := c.localNodeInfo() + return ni.PublicKey() +} + +func (c *cfg) Address() string { + ni := c.localNodeInfo() + return ni.Address() +} + +func (c *usedSpaceService) PublicKey() []byte { + ni := c.cfg.localNodeInfo() + + return ni.PublicKey() +} + +func (c *usedSpaceService) Address() string { + ni := c.cfg.localNodeInfo() + + return ni.Address() +} + +func (c *usedSpaceService) AnnounceUsedSpace(ctx context.Context, req *containerV2.AnnounceUsedSpaceRequest) (*containerV2.AnnounceUsedSpaceResponse, error) { + var passedRoute []loadroute.ServerInfo + + for hdr := req.GetVerificationHeader(); hdr != nil; hdr = hdr.GetOrigin() { + passedRoute = append(passedRoute, &onlyKeyRemoteServerInfo{ + key: hdr.GetBodySignature().GetKey(), + }) + } + + for left, right := 0, len(passedRoute)-1; left < right; left, right = left+1, right-1 { + passedRoute[left], passedRoute[right] = passedRoute[right], passedRoute[left] + } + + passedRoute = append(passedRoute, c) + + w, err := c.loadWriterProvider.InitWriter(loadroute.NewRouteContext(ctx, passedRoute)) + if err != nil { + return nil, errors.Wrap(err, "could not initialize container's used space writer") + } + + for _, aV2 := range req.GetBody().GetAnnouncements() { + if err := c.processLoadValue(ctx, *containerSDK.NewAnnouncementFromV2(aV2), passedRoute, w); err != nil { + return nil, err + } + } + + respBody := new(containerV2.AnnounceUsedSpaceResponseBody) + + resp := new(containerV2.AnnounceUsedSpaceResponse) + resp.SetBody(respBody) + + return resp, nil +} + +var errNodeOutsideContainer = errors.New("node outside the container") + +type onlyKeyRemoteServerInfo struct { + key []byte +} + +func (i *onlyKeyRemoteServerInfo) PublicKey() []byte { + return i.key +} + +func (*onlyKeyRemoteServerInfo) Address() string { + return "" +} + +func (l *loadPlacementBuilder) isNodeFromContainerKey(epoch uint64, cid *containerSDK.ID, key []byte) (bool, error) { + cnrNodes, _, err := l.buildPlacement(epoch, cid) + if err != nil { + return false, err + } + + for _, vector := range cnrNodes.Replicas() { + for _, node := range vector { + if bytes.Equal(node.PublicKey(), key) { + return true, nil + } + } + } + + return false, nil +} + +func (c *usedSpaceService) processLoadValue(ctx context.Context, a containerSDK.UsedSpaceAnnouncement, + route []loadroute.ServerInfo, w loadcontroller.Writer) error { + fromCnr, err := c.loadPlacementBuilder.isNodeFromContainerKey(a.Epoch(), a.ContainerID(), route[0].PublicKey()) + if err != nil { + return errors.Wrap(err, "could not verify that the sender belongs to the container") + } else if !fromCnr { + return errNodeOutsideContainer + } + + err = loadroute.CheckRoute(c.routeBuilder, a, route) + if err != nil { + return errors.Wrap(err, "wrong route of container's used space value") + } + + err = w.Put(a) + if err != nil { + return errors.Wrap(err, "could not write container's used space value") + } + + return nil +}