From 0fb9b43634362f315dc169083fb0ede3723c1874 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Tue, 22 Oct 2024 17:25:20 +0400 Subject: [PATCH 1/5] *: Cache network settings Closes #247. Signed-off-by: Evgenii Baidakov --- handlers/api.go | 8 ++++++ internal/cache/networkinfo.go | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 internal/cache/networkinfo.go diff --git a/handlers/api.go b/handlers/api.go index 64c5771..55b915f 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -11,8 +11,10 @@ import ( "github.com/labstack/echo/v4" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver" + "github.com/nspcc-dev/neofs-rest-gw/internal/cache" "github.com/nspcc-dev/neofs-rest-gw/internal/util" "github.com/nspcc-dev/neofs-rest-gw/metrics" + "github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/session" "github.com/nspcc-dev/neofs-sdk-go/user" @@ -45,6 +47,10 @@ type SessionToken struct { Verb session.ContainerVerb } +type networkInfoGetter interface { + NetworkInfo(ctx context.Context) (netmap.NetworkInfo, error) +} + const ( // bearerCookieName is the name of the bearer cookie. bearerCookieName = "Bearer" @@ -75,6 +81,7 @@ func NewAPI(prm *PrmAPI) (*RestAPI, error) { pprofService: prm.PprofService, gateMetric: prm.GateMetric, serviceShutdownTimeout: prm.ServiceShutdownTimeout, + networkInfoGetter: cache.NewNetworkInfoCache(prm.Pool), }, nil } @@ -141,6 +148,7 @@ type RestAPI struct { prometheusService *metrics.Service pprofService *metrics.Service serviceShutdownTimeout time.Duration + networkInfoGetter networkInfoGetter } func (a *RestAPI) StartCallback() { diff --git a/internal/cache/networkinfo.go b/internal/cache/networkinfo.go new file mode 100644 index 0000000..daa9161 --- /dev/null +++ b/internal/cache/networkinfo.go @@ -0,0 +1,51 @@ +package cache + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/nspcc-dev/neofs-sdk-go/client" + "github.com/nspcc-dev/neofs-sdk-go/netmap" + "github.com/nspcc-dev/neofs-sdk-go/pool" +) + +type ( + // NetworkInfo is cache wrapper for the network info. + NetworkInfo struct { + p *pool.Pool + ttl time.Duration + + mu *sync.Mutex + validUntil time.Time + ni netmap.NetworkInfo + } +) + +func NewNetworkInfoCache(p *pool.Pool) *NetworkInfo { + return &NetworkInfo{ + p: p, + mu: &sync.Mutex{}, + } +} + +func (n *NetworkInfo) NetworkInfo(ctx context.Context) (netmap.NetworkInfo, error) { + n.mu.Lock() + defer n.mu.Unlock() + + if n.validUntil.After(time.Now()) { + return n.ni, nil + } + + ni, err := n.p.NetworkInfo(ctx, client.PrmNetworkInfo{}) + if err != nil { + return netmap.NetworkInfo{}, fmt.Errorf("get network info: %w", err) + } + + n.ttl = time.Duration(int64(ni.EpochDuration())/2*ni.MsPerBlock()) * time.Millisecond + n.validUntil = time.Now().Add(n.ttl) + n.ni = ni + + return ni, nil +} From 2b5cecda61a77f45042ab8ef172d95c9511e4a41 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Tue, 22 Oct 2024 17:25:58 +0400 Subject: [PATCH 2/5] handler: Setup HomomorphicHashing for container Signed-off-by: Evgenii Baidakov --- handlers/containers.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/handlers/containers.go b/handlers/containers.go index 53c552d..72b6322 100644 --- a/handlers/containers.go +++ b/handlers/containers.go @@ -64,7 +64,7 @@ func (a *RestAPI) PutContainer(ctx echo.Context, params apiserver.PutContainerPa return ctx.JSON(http.StatusBadRequest, resp) } - cnrID, err := createContainer(ctx.Request().Context(), a.pool, stoken, body, params, a.signer) + cnrID, err := createContainer(ctx.Request().Context(), a.pool, stoken, body, params, a.signer, a.networkInfoGetter) if err != nil { resp := a.logAndGetErrorResponse("create container", err) return ctx.JSON(http.StatusBadRequest, resp) @@ -381,7 +381,7 @@ func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*apiserv return tableResp, nil } -func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, request apiserver.ContainerPutInfo, params apiserver.PutContainerParams, signer user.Signer) (cid.ID, error) { +func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, request apiserver.ContainerPutInfo, params apiserver.PutContainerParams, signer user.Signer, networkInfoGetter networkInfoGetter) (cid.ID, error) { if request.PlacementPolicy == "" { request.PlacementPolicy = defaultPlacementPolicy } @@ -406,6 +406,15 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container cnr.SetBasicACL(basicACL) cnr.SetOwner(stoken.Issuer()) + ni, err := networkInfoGetter.NetworkInfo(ctx) + if err != nil { + return cid.ID{}, fmt.Errorf("couldn't get network info: %w", err) + } + + if ni.HomomorphicHashingDisabled() { + cnr.DisableHomomorphicHashing() + } + cnr.SetCreationTime(time.Now()) if request.ContainerName != "" { From d36fa60d2331d8099beb66a44c349f4a0cd5859c Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Tue, 22 Oct 2024 17:29:18 +0400 Subject: [PATCH 3/5] handler: Use networkInfoGetter for getEpochDurations Signed-off-by: Evgenii Baidakov --- handlers/newObjects.go | 2 +- handlers/objects.go | 4 ++-- handlers/util.go | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/handlers/newObjects.go b/handlers/newObjects.go index 00fbab5..68d5ae6 100644 --- a/handlers/newObjects.go +++ b/handlers/newObjects.go @@ -62,7 +62,7 @@ func (a *RestAPI) NewUploadContainerObject(ctx echo.Context, containerID apiserv addExpirationHeaders(filtered, params) if needParseExpiration(filtered) { - epochDuration, err := getEpochDurations(ctx.Request().Context(), a.pool) + epochDuration, err := getEpochDurations(ctx.Request().Context(), a.networkInfoGetter) if err != nil { resp := a.logAndGetErrorResponse("could not get epoch durations from network info", err) return ctx.JSON(http.StatusBadRequest, resp) diff --git a/handlers/objects.go b/handlers/objects.go index 2005aa8..a11086c 100644 --- a/handlers/objects.go +++ b/handlers/objects.go @@ -105,7 +105,7 @@ func (a *RestAPI) PutObject(ctx echo.Context, params apiserver.PutObjectParams) DefaultTimestamp: a.defaultTimestamp, DefaultFileName: body.FileName, } - attributes, err := getObjectAttributes(ctx.Request().Context(), a.pool, body.Attributes, prm) + attributes, err := getObjectAttributes(ctx.Request().Context(), a.networkInfoGetter, body.Attributes, prm) if err != nil { resp := a.logAndGetErrorResponse("failed to get object attributes", err) return ctx.JSON(http.StatusBadRequest, resp) @@ -940,7 +940,7 @@ func (a *RestAPI) UploadContainerObject(ctx echo.Context, containerID apiserver. } if needParseExpiration(filtered) { - epochDuration, err := getEpochDurations(ctx.Request().Context(), a.pool) + epochDuration, err := getEpochDurations(ctx.Request().Context(), a.networkInfoGetter) if err != nil { resp := a.logAndGetErrorResponse("could not get epoch durations from network info", err) return ctx.JSON(http.StatusBadRequest, resp) diff --git a/handlers/util.go b/handlers/util.go index cdbdb96..49478cb 100644 --- a/handlers/util.go +++ b/handlers/util.go @@ -19,7 +19,6 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/container/acl" "github.com/nspcc-dev/neofs-sdk-go/object" oid "github.com/nspcc-dev/neofs-sdk-go/object/id" - "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/session" "go.uber.org/zap" ) @@ -55,7 +54,7 @@ const ( limitDefault = 100 ) -func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver.Attribute, prm PrmAttributes) ([]object.Attribute, error) { +func getObjectAttributes(ctx context.Context, networkInfoGetter networkInfoGetter, attrs []apiserver.Attribute, prm PrmAttributes) ([]object.Attribute, error) { headers := make(map[string]string, len(attrs)) for _, attr := range attrs { @@ -64,7 +63,7 @@ func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver delete(headers, object.AttributeFileName) if needParseExpiration(headers) { - epochDuration, err := getEpochDurations(ctx, pool) + epochDuration, err := getEpochDurations(ctx, networkInfoGetter) if err != nil { return nil, fmt.Errorf("could not get epoch durations from network info: %w", err) } @@ -91,8 +90,8 @@ func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver return attributes, nil } -func getEpochDurations(ctx context.Context, p *pool.Pool) (*epochDurations, error) { - networkInfo, err := p.NetworkInfo(ctx, client.PrmNetworkInfo{}) +func getEpochDurations(ctx context.Context, networkInfoGetter networkInfoGetter) (*epochDurations, error) { + networkInfo, err := networkInfoGetter.NetworkInfo(ctx) if err != nil { return nil, err } From 262e100a5395c79d90906d53486c5a14f8be39ab Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Tue, 22 Oct 2024 17:31:09 +0400 Subject: [PATCH 4/5] handler: Use networkInfoGetter for getCurrentEpoch Signed-off-by: Evgenii Baidakov --- handlers/auth.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/handlers/auth.go b/handlers/auth.go index 6ce3cc7..dce4a4c 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -11,9 +11,7 @@ import ( "github.com/labstack/echo/v4" "github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver" "github.com/nspcc-dev/neofs-rest-gw/internal/util" - "github.com/nspcc-dev/neofs-sdk-go/client" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" - "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/user" ) @@ -91,10 +89,10 @@ func (a *RestAPI) Auth(ctx echo.Context, params apiserver.AuthParams) error { if isObject { prm := newObjectParams(commonPrm, token) - response[i], err = prepareObjectToken(ctx.Request().Context(), prm, a.pool, a.signer.UserID()) + response[i], err = prepareObjectToken(ctx.Request().Context(), prm, a.networkInfoGetter, a.signer.UserID()) } else { prm := newContainerParams(commonPrm, token) - response[i], err = prepareContainerTokens(ctx.Request().Context(), prm, a.pool, a.signer.Public()) + response[i], err = prepareContainerTokens(ctx.Request().Context(), prm, a.networkInfoGetter, a.signer.Public()) } if err != nil { @@ -136,7 +134,7 @@ func (a *RestAPI) FormBinaryBearer(ctx echo.Context, params apiserver.FormBinary return ctx.JSON(http.StatusOK, resp) } -func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *pool.Pool, owner user.ID) (*apiserver.TokenResponse, error) { +func prepareObjectToken(ctx context.Context, params objectTokenParams, networkInfoGetter networkInfoGetter, owner user.ID) (*apiserver.TokenResponse, error) { btoken, err := util.ToNativeObjectToken(params.Records) if err != nil { return nil, fmt.Errorf("couldn't transform token to native: %w", err) @@ -152,7 +150,7 @@ func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *poo btoken.ForUser(owner) } - iat, exp, err := getTokenLifetime(ctx, pool, params.XBearerLifetime) + iat, exp, err := getTokenLifetime(ctx, networkInfoGetter, params.XBearerLifetime) if err != nil { return nil, fmt.Errorf("couldn't get lifetime: %w", err) } @@ -168,8 +166,8 @@ func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *poo }, nil } -func prepareContainerTokens(ctx context.Context, params containerTokenParams, pool *pool.Pool, pubKey neofscrypto.PublicKey) (*apiserver.TokenResponse, error) { - iat, exp, err := getTokenLifetime(ctx, pool, params.XBearerLifetime) +func prepareContainerTokens(ctx context.Context, params containerTokenParams, networkInfoGetter networkInfoGetter, pubKey neofscrypto.PublicKey) (*apiserver.TokenResponse, error) { + iat, exp, err := getTokenLifetime(ctx, networkInfoGetter, params.XBearerLifetime) if err != nil { return nil, fmt.Errorf("couldn't get lifetime: %w", err) } @@ -204,8 +202,8 @@ func prepareContainerTokens(ctx context.Context, params containerTokenParams, po }, nil } -func getCurrentEpoch(ctx context.Context, p *pool.Pool) (uint64, error) { - netInfo, err := p.NetworkInfo(ctx, client.PrmNetworkInfo{}) +func getCurrentEpoch(ctx context.Context, networkInfoGetter networkInfoGetter) (uint64, error) { + netInfo, err := networkInfoGetter.NetworkInfo(ctx) if err != nil { return 0, fmt.Errorf("couldn't get netwokr info: %w", err) } @@ -213,8 +211,8 @@ func getCurrentEpoch(ctx context.Context, p *pool.Pool) (uint64, error) { return netInfo.CurrentEpoch(), nil } -func getTokenLifetime(ctx context.Context, p *pool.Pool, expDuration uint64) (uint64, uint64, error) { - currEpoch, err := getCurrentEpoch(ctx, p) +func getTokenLifetime(ctx context.Context, networkInfoGetter networkInfoGetter, expDuration uint64) (uint64, uint64, error) { + currEpoch, err := getCurrentEpoch(ctx, networkInfoGetter) if err != nil { return 0, 0, err } From 309119bcbd1b666078c80b1ff663d9f9c82f87f6 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Wed, 23 Oct 2024 08:33:24 +0400 Subject: [PATCH 5/5] handler: Update NetworkInfo cache on GetNetworkInfo request Signed-off-by: Evgenii Baidakov --- handlers/api.go | 1 + handlers/network.go | 2 ++ internal/cache/networkinfo.go | 12 +++++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/handlers/api.go b/handlers/api.go index 55b915f..dea19ea 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -49,6 +49,7 @@ type SessionToken struct { type networkInfoGetter interface { NetworkInfo(ctx context.Context) (netmap.NetworkInfo, error) + StoreNetworkInfo(ni netmap.NetworkInfo) } const ( diff --git a/handlers/network.go b/handlers/network.go index 2c57a64..e3c26fd 100644 --- a/handlers/network.go +++ b/handlers/network.go @@ -17,6 +17,8 @@ func (a *RestAPI) GetNetworkInfo(ctx echo.Context) error { return ctx.JSON(http.StatusBadRequest, resp) } + a.networkInfoGetter.StoreNetworkInfo(networkInfo) + var resp apiserver.NetworkInfoOK resp.AuditFee = networkInfo.AuditFee() resp.StoragePrice = networkInfo.StoragePrice() diff --git a/internal/cache/networkinfo.go b/internal/cache/networkinfo.go index daa9161..b367ac3 100644 --- a/internal/cache/networkinfo.go +++ b/internal/cache/networkinfo.go @@ -43,9 +43,19 @@ func (n *NetworkInfo) NetworkInfo(ctx context.Context) (netmap.NetworkInfo, erro return netmap.NetworkInfo{}, fmt.Errorf("get network info: %w", err) } + n.update(ni) + + return ni, nil +} + +func (n *NetworkInfo) update(ni netmap.NetworkInfo) { n.ttl = time.Duration(int64(ni.EpochDuration())/2*ni.MsPerBlock()) * time.Millisecond n.validUntil = time.Now().Add(n.ttl) n.ni = ni +} - return ni, nil +func (n *NetworkInfo) StoreNetworkInfo(ni netmap.NetworkInfo) { + n.mu.Lock() + n.update(ni) + n.mu.Unlock() }