Separate type for object header #247

Open
opened 2025-12-28 18:07:34 +00:00 by sami · 8 comments
Owner

Originally created by @cthulhu-rider on GitHub (Dec 6, 2024).

currently, object provides Object structure type, but no Header one. This type would be helpful for HEAD ops (Client, node storage, etc.). Now such ops return instances of the Object type with unset payload field. I see following drawbacks in this approach:

  1. header is always requested by object ID, and the resulting instance has the one. This is redundant now
  2. header encoding becomes more tricky. This leads to additions like https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.MarshalHeaderJSON, which is not rly bad, but could be provided apriori. For binary encoding, https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.CutPayload is used, but it adds ID to the result while these BLOBS are usually stored by ID key itself
  3. entity appears in the protocol and in different system parts, it is quite natural for it to have a type
  4. in code, the header is not distinguished from the object, although it is a narrower type. Because of this, comments have to be added, which weakens the type system

Describe the solution you'd like

type Header struct { /* container, owner, ... */ }
type Object struct {
	Header
	id        oid.ID
	signature neofscrypto.Signature
	payload   []byte
}
func (*Client) HeadObject(...) (object.Header, neofscrypto.Signature, error)

Additional context

iirc @carpawell had questions why there is no header type. I couldnt find any issue, pls share if smth already exists

Originally created by @cthulhu-rider on GitHub (Dec 6, 2024). ## Is your feature request related to a problem? Please describe. currently, `object` provides `Object` structure type, but no `Header` one. This type would be helpful for HEAD ops (`Client`, node storage, etc.). Now such ops return instances of the `Object` type with unset payload field. I see following drawbacks in this approach: 1. header is always requested by object ID, and the resulting instance has the one. This is redundant now 2. header encoding becomes more tricky. This leads to additions like https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.MarshalHeaderJSON, which is not rly bad, but could be provided apriori. For binary encoding, https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.CutPayload is used, but it adds ID to the result while these BLOBS are usually stored by ID key itself 3. entity appears in the protocol and in different system parts, it is quite natural for it to have a type 4. in code, the header is not distinguished from the object, although it is a narrower type. Because of this, comments have to be added, which weakens the type system ## Describe the solution you'd like ```go type Header struct { /* container, owner, ... */ } type Object struct { Header id oid.ID signature neofscrypto.Signature payload []byte } func (*Client) HeadObject(...) (object.Header, neofscrypto.Signature, error) ``` ## Additional context iirc @carpawell had questions why there is no header type. I couldnt find any issue, pls share if smth already exists
Author
Owner

@carpawell commented on GitHub (Dec 6, 2024):

I always did not understand why there is no header while IMO it is a natural understanding for our HEAD operation and objects in general: every object has a header and every object has a payload. Sometimes we need only a header and vice versa. I have not opened any issues about it.

@carpawell commented on GitHub (Dec 6, 2024): I always did not understand why there is no header while IMO it is a natural understanding for our HEAD operation and objects in general: every object has a header and every object has a payload. Sometimes we need only a header and vice versa. I have not opened any issues about it.
Author
Owner

@roman-khimov commented on GitHub (Dec 9, 2024):

Yeah, we need this type, passing object.Object and doing CutPayload() tricks is very confusing, you never know what you have in code: a complete object or header only. But we need it to follow proto spec as well, signature is a part of the header IIRC.

@roman-khimov commented on GitHub (Dec 9, 2024): Yeah, we need this type, passing `object.Object` and doing `CutPayload()` tricks is very confusing, you never know what you have in code: a complete object or header only. But we need it to follow proto spec as well, signature is a part of the header IIRC.
Author
Owner

@cthulhu-rider commented on GitHub (Dec 9, 2024):

signature is not a part of header itself nspcc-dev/neofs-api@e66b25d4bf/object/types.proto (L226), so it's transmitted beside nspcc-dev/neofs-api@e66b25d4bf/object/service.proto (L462)

@cthulhu-rider commented on GitHub (Dec 9, 2024): signature is not a part of header itself https://github.com/nspcc-dev/neofs-api/blob/e66b25d4bf2afc4472023e1e2c2467f694f5a0e1/object/types.proto#L226, so it's transmitted beside https://github.com/nspcc-dev/neofs-api/blob/e66b25d4bf2afc4472023e1e2c2467f694f5a0e1/object/service.proto#L462
Author
Owner

@roman-khimov commented on GitHub (Dec 9, 2024):

Header, SignedHeader, Object?

@roman-khimov commented on GitHub (Dec 9, 2024): Header, SignedHeader, Object?
Author
Owner

@cthulhu-rider commented on GitHub (Dec 9, 2024):

Header, SignedHeader, Object?

SignedHeader includes ID here?

@cthulhu-rider commented on GitHub (Dec 9, 2024): > Header, SignedHeader, Object? `SignedHeader` includes ID here?
Author
Owner

@roman-khimov commented on GitHub (Dec 9, 2024):

It's so tempting for me to make it a method with cached internal value (transaction.Transaction). We need to evaluate real use cases, I know we have a number of uses for SignedHeader (maybe even more so than for Header alone).

@roman-khimov commented on GitHub (Dec 9, 2024): It's so tempting for me to make it a method with cached internal value (`transaction.Transaction`). We need to evaluate real use cases, I know we have a number of uses for `SignedHeader` (maybe even more so than for `Header` alone).
Author
Owner

@cthulhu-rider commented on GitHub (Dec 9, 2024):

cached values ​​are often a source of errors. I would stick with simple tuples with open logic

real use cases

https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.MarshalHeaderJSON is what i remember. nspcc-dev/neo-go@5f92da21fa/pkg/services/oracle/neofs/neofs.go (L185). The getObjHeader could return object.Header

various tuples can be used:

and i remember no usecase where we need (ID, signature, header) tuple

finally, for now i see HeaderHeaderWithSignatureObject type system

@cthulhu-rider commented on GitHub (Dec 9, 2024): cached values ​​are often a source of errors. I would stick with simple tuples with open logic > real use cases https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.MarshalHeaderJSON is what i remember. https://github.com/nspcc-dev/neo-go/blob/5f92da21fa43e4fe80fb965c78d5d244b6003ffd/pkg/services/oracle/neofs/neofs.go#L185. The `getObjHeader` could return `object.Header` various tuples can be used: - API HEAD returns https://github.com/nspcc-dev/neofs-api/blob/e66b25d4bf2afc4472023e1e2c2467f694f5a0e1/object/service.proto#L439-L452, no ID - metastorages store meta info by ID key, so they expect some kind of `HeaderWithSignature` too and i remember no usecase where we need (ID, signature, header) tuple finally, for now i see `Header` ∈ `HeaderWithSignature` ∈ `Object` type system
Author
Owner

@cthulhu-rider commented on GitHub (Dec 9, 2024):

it must be noted that transition to the heading types must be carried out carefully. For example, CutPayload returns an object. So, nspcc-dev/neofs-node@918307b073/pkg/local_object_storage/metabase/put.go (L186) means that metabase stores (ID, signature, header) tuples. Not rly good to store storage key in the value, but it is what it is, updated code must take this into account. Normally, metabase could store HeaderWithSignature

ALSO!!!: do not forget about field numbers. Object and HeaderWithSignature have different ones. Field nums are essential for Marshal and any protobuf functionality

@cthulhu-rider commented on GitHub (Dec 9, 2024): it must be noted that transition to the heading types must be carried out carefully. For example, [`CutPayload`](https://pkg.go.dev/github.com/nspcc-dev/neofs-sdk-go/object#Object.CutPayload) returns an _object_. So, https://github.com/nspcc-dev/neofs-node/blob/918307b0739feb086416e667497c676170e0c9ca/pkg/local_object_storage/metabase/put.go#L186 means that metabase stores (ID, signature, header) tuples. Not rly good to store storage key in the value, but it is what it is, updated code must take this into account. Normally, metabase could store `HeaderWithSignature` ALSO!!!: do not forget about field numbers. `Object` and `HeaderWithSignature` have different ones. Field nums are essential for `Marshal` and any protobuf functionality
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nspcc-dev/neofs-sdk-go#247
No description provided.