diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c27196377..9d52da6242 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Changelog for NeoFS Node ## [Unreleased] ### Added +- Initial support for meta-on-chain for objects (#2877) ### Fixed diff --git a/pkg/morph/client/container/put.go b/pkg/morph/client/container/put.go index aec2665fd2..fa8205ed1c 100644 --- a/pkg/morph/client/container/put.go +++ b/pkg/morph/client/container/put.go @@ -5,6 +5,7 @@ import ( containercore "github.com/nspcc-dev/neofs-node/pkg/core/container" "github.com/nspcc-dev/neofs-node/pkg/morph/client" + containerSDK "github.com/nspcc-dev/neofs-sdk-go/container" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" ) @@ -21,6 +22,10 @@ func Put(c *Client, cnr containercore.Container) (*cid.ID, error) { prm.SetContainer(data) prm.SetName(d.Name()) prm.SetZone(d.Zone()) + switch metaAttribute(cnr.Value) { + case "optimistic", "strict": + prm.EnableMeta() + } if cnr.Session != nil { prm.SetToken(cnr.Session.Marshal()) @@ -41,12 +46,13 @@ func Put(c *Client, cnr containercore.Container) (*cid.ID, error) { // PutPrm groups parameters of Put operation. type PutPrm struct { - cnr []byte - key []byte - sig []byte - token []byte - name string - zone string + cnr []byte + key []byte + sig []byte + token []byte + name string + zone string + enableMetaOnChain bool client.InvokePrmOptional } @@ -81,6 +87,11 @@ func (p *PutPrm) SetZone(zone string) { p.zone = zone } +// EnableMeta enables meta-on-chain. +func (p *PutPrm) EnableMeta() { + p.enableMetaOnChain = true +} + // Put saves binary container with its session token, key and signature // in NeoFS system through Container contract call. // @@ -91,21 +102,10 @@ func (c *Client) Put(p PutPrm) error { return errNilArgument } - var ( - method string - prm client.InvokePrm - ) - - if p.name != "" { - method = putNamedMethod - prm.SetArgs(p.cnr, p.sig, p.key, p.token, p.name, p.zone) - } else { - method = putMethod - prm.SetArgs(p.cnr, p.sig, p.key, p.token) - } - - prm.SetMethod(method) + var prm client.InvokePrm + prm.SetMethod(putMethod) prm.InvokePrmOptional = p.InvokePrmOptional + prm.SetArgs(p.cnr, p.sig, p.key, p.token, p.name, p.zone, p.enableMetaOnChain) // no magic bugs with notary requests anymore, this operation should // _always_ be notary signed so make it one more time even if it is @@ -114,7 +114,11 @@ func (c *Client) Put(p PutPrm) error { err := c.client.Invoke(prm) if err != nil { - return fmt.Errorf("could not invoke method (%s): %w", method, err) + return fmt.Errorf("could not invoke method (%s): %w", putMethod, err) } return nil } + +func metaAttribute(cnr containerSDK.Container) string { + return cnr.Attribute("__NEOFS__METAINFO_CONSISTENCY") +} diff --git a/pkg/morph/event/container/put.go b/pkg/morph/event/container/put.go index ea2394e770..a22828f1c6 100644 --- a/pkg/morph/event/container/put.go +++ b/pkg/morph/event/container/put.go @@ -16,6 +16,9 @@ type Put struct { signature []byte publicKey []byte token []byte + name string + zone string + metaOnChain bool // For notary notifications only. // Contains raw transactions of notary request. diff --git a/pkg/morph/event/container/put_notary.go b/pkg/morph/event/container/put_notary.go index bf5d186464..0dba322ac1 100644 --- a/pkg/morph/event/container/put_notary.go +++ b/pkg/morph/event/container/put_notary.go @@ -32,6 +32,18 @@ func (p *Put) setToken(v []byte) { } } +func (p *Put) setName(v string) { + p.name = v +} + +func (p *Put) setZone(v string) { + p.zone = v +} + +func (p *Put) setMetaOnChain(v bool) { + p.metaOnChain = v +} + var putFieldSetters = []func(*Put, []byte){ // order on stack is reversed (*Put).setToken, @@ -56,6 +68,34 @@ func parsePutNotary(ev *Put, raw *payload.P2PNotaryRequest, ops []event.Op) erro fieldNum = 0 ) + switch len(ops) { + case expectedItemNumPut + 3: + enableMeta, err := event.BoolFromOpcode(ops[0]) + if err != nil { + return fmt.Errorf("parse arg meta: %w", err) + } + ev.setMetaOnChain(enableMeta) + + ops = ops[1:] + + err = parseNamedArgs(ev, ops) + if err != nil { + return err + } + + ops = ops[2:] + case expectedItemNumPut + 2: + err := parseNamedArgs(ev, ops) + if err != nil { + return err + } + + ops = ops[2:] + case expectedItemNumPut: + default: + return fmt.Errorf("unknown number of args: %d", len(ops)) + } + for _, op := range ops { currentOp = op.Code() @@ -104,14 +144,9 @@ func ParsePutNamedNotary(ne event.NotaryEvent) (event.Event, error) { err error ) - ev.zone, err = event.StringFromOpcode(ops[0]) + err = parseNamedArgs(&ev, ops) if err != nil { - return nil, fmt.Errorf("parse arg zone: %w", err) - } - - ev.name, err = event.StringFromOpcode(ops[1]) - if err != nil { - return nil, fmt.Errorf("parse arg name: %w", err) + return nil, err } err = parsePutNotary(&ev.Put, ne.Raw(), ops[putNamedAdditionalArgs:]) @@ -121,3 +156,25 @@ func ParsePutNamedNotary(ne event.NotaryEvent) (event.Event, error) { return ev, nil } + +type putEvNamed interface { + setName(v string) + setZone(v string) +} + +func parseNamedArgs(p putEvNamed, ops []event.Op) error { + zone, err := event.StringFromOpcode(ops[0]) + if err != nil { + return fmt.Errorf("parse arg zone: %w", err) + } + + name, err := event.StringFromOpcode(ops[1]) + if err != nil { + return fmt.Errorf("parse arg name: %w", err) + } + + p.setZone(zone) + p.setName(name) + + return nil +} diff --git a/pkg/morph/event/opcodes.go b/pkg/morph/event/opcodes.go index 3385c2eace..069748ba70 100644 --- a/pkg/morph/event/opcodes.go +++ b/pkg/morph/event/opcodes.go @@ -37,6 +37,18 @@ func BytesFromOpcode(op Op) ([]byte, error) { } } +// BoolFromOpcode tries to retrieve bool from Op. +func BoolFromOpcode(op Op) (bool, error) { + switch code := op.Code(); code { + case opcode.PUSHT: + return true, nil + case opcode.PUSHF: + return false, nil + default: + return false, fmt.Errorf("unexpected ByteArray opcode %s", code) + } +} + // IntFromOpcode tries to retrieve int from Op. func IntFromOpcode(op Op) (int64, error) { switch code := op.Code(); {