From d1f2c376098e0835a7115cbfc1f325c4093ed238 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Fri, 30 Aug 2024 11:48:12 +0400 Subject: [PATCH 1/2] *: Store nonce for uploaded objects Close #986. It prevents to generate same ID for the two identical objects in the same seconds. Signed-off-by: Evgenii Baidakov --- internal/neofs/neofs.go | 14 +++++++++++ internal/neofs/neofs_test.go | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/internal/neofs/neofs.go b/internal/neofs/neofs.go index 55c527d3..b69f0dff 100644 --- a/internal/neofs/neofs.go +++ b/internal/neofs/neofs.go @@ -3,7 +3,9 @@ package neofs import ( "bytes" "context" + "crypto/rand" "crypto/sha256" + "encoding/base64" "encoding/hex" "errors" "fmt" @@ -55,6 +57,11 @@ type NeoFS struct { buffers *sync.Pool } +const ( + objectNonceSize = 8 + objectNonceAttribute = "__NEOFS__NONCE" +) + // NewNeoFS creates new NeoFS using provided pool.Pool. func NewNeoFS(p *pool.Pool, signer user.Signer, anonSigner user.Signer, cfg Config, epochGetter EpochGetter) *NeoFS { buffers := sync.Pool{} @@ -268,6 +275,13 @@ func (x *NeoFS) CreateObject(ctx context.Context, prm layer.PrmObjectCreate) (oi attrs = append(attrs, *a) } + nonce := make([]byte, objectNonceSize) + if _, err := rand.Read(nonce); err != nil { + return oid.ID{}, fmt.Errorf("object nonce: %w", err) + } + objectNonceAttr := object.NewAttribute(objectNonceAttribute, base64.StdEncoding.EncodeToString(nonce)) + attrs = append(attrs, *objectNonceAttr) + var obj object.Object obj.SetContainerID(prm.Container) obj.SetOwnerID(&prm.Creator) diff --git a/internal/neofs/neofs_test.go b/internal/neofs/neofs_test.go index 63fd9920..10c534d2 100644 --- a/internal/neofs/neofs_test.go +++ b/internal/neofs/neofs_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/rand" + "encoding/base64" "fmt" "io" "runtime" @@ -19,7 +20,10 @@ import ( "github.com/nspcc-dev/neofs-sdk-go/container" "github.com/nspcc-dev/neofs-sdk-go/container/acl" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test" + neofscryptotest "github.com/nspcc-dev/neofs-sdk-go/crypto/test" "github.com/nspcc-dev/neofs-sdk-go/netmap" + "github.com/nspcc-dev/neofs-sdk-go/object" "github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/user" "github.com/nspcc-dev/neofs-sdk-go/waiter" @@ -234,3 +238,45 @@ func uploadDownload(ctx context.Context, t *testing.T, neo *NeoFS, p *pool.Pool, require.True(t, bytes.Equal(payload, pl)) } } + +func TestObjectNonce(t *testing.T) { + var ( + signer = user.NewAutoIDSignerRFC6979(neofscryptotest.Signer().ECDSAPrivateKey) + cnrID = cidtest.ID() + payload = []byte{1, 2, 3, 4, 5} + uid = signer.UserID() + m = make(map[string]int) + ts = time.Now().Unix() + attrTS = object.NewAttribute(object.AttributeTimestamp, strconv.FormatInt(ts, 10)) + ) + + for i := 0; i < 10; i++ { + var ( + obj object.Object + nonce = make([]byte, objectNonceSize) + ) + + _, err := rand.Read(nonce) + require.NoError(t, err) + + obj.SetContainerID(cnrID) + obj.SetOwnerID(&uid) + obj.SetPayloadSize(uint64(len(payload))) + obj.SetPayload(payload) + + var ( + attr = object.NewAttribute(objectNonceAttribute, base64.StdEncoding.EncodeToString(nonce)) + attrs = []object.Attribute{*attrTS, *attr} + ) + + obj.SetAttributes(attrs...) + require.NoError(t, obj.CalculateAndSetID()) + + m[obj.GetID().String()]++ + } + + // each ID is uniq + for _, v := range m { + require.Equal(t, 1, v) + } +} From 550251bde9756dc9f19bff870f8f0583a95d444f Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Fri, 30 Aug 2024 11:48:39 +0400 Subject: [PATCH 2/2] layer: Add separate log for delete object Signed-off-by: Evgenii Baidakov --- api/layer/object.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/api/layer/object.go b/api/layer/object.go index f1cc5da7..7bb77674 100644 --- a/api/layer/object.go +++ b/api/layer/object.go @@ -467,7 +467,18 @@ func (n *layer) objectDelete(ctx context.Context, bktInfo *data.BucketInfo, idOb n.cache.DeleteObject(newAddress(bktInfo.CID, idObj)) - return n.neoFS.DeleteObject(ctx, prm) + err := n.neoFS.DeleteObject(ctx, prm) + + reqInfo := api.GetReqInfo(ctx) + n.log.Debug("delete object", + zap.String("reqId", reqInfo.RequestID), + zap.String("bucket", bktInfo.Name), + zap.Stringer("cid", bktInfo.CID), + zap.Stringer("oid", idObj), + zap.Error(err), + ) + + return err } // objectPutAndHash prepare auth parameters and invoke neofs.CreateObject.