From 3759d4d833b2cfd9e99827b7503fe11d58e1263e Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 9 Dec 2025 20:13:16 +0300 Subject: [PATCH 1/2] container: Improve docs for OK `Put` / `Delete` / `SetExtendedACL` Since e3415229a674a3af8021815a4dfcf6ea820da286, these ops are sync, so their OK status mean complete success. Refs #353. Signed-off-by: Leonard Lyubich --- container/service.proto | 6 +++--- proto-docs/container.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/container/service.proto b/container/service.proto index 91056b35..9fdc2001 100644 --- a/container/service.proto +++ b/container/service.proto @@ -22,7 +22,7 @@ service ContainerService { // // Statuses: // - **OK** (0, SECTION_SUCCESS): \ - // request to save the container has been sent to FS chain; + // container successfully created;; // - Common failures (SECTION_FAILURE_COMMON); // - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ // transaction was sent but not executed within the deadline. @@ -38,7 +38,7 @@ service ContainerService { // // Statuses: // - **OK** (0, SECTION_SUCCESS): \ - // request to remove the container has been sent to FS chain; + // container successfully removed; // - Common failures (SECTION_FAILURE_COMMON); // - **CONTAINER_LOCKED** (3074, SECTION_CONTAINER): \ // deleting a locked container is prohibited; @@ -71,7 +71,7 @@ service ContainerService { // // Statuses: // - **OK** (0, SECTION_SUCCESS): \ - // request to save container eACL has been sent to FS chain; + // container eACL successfully set; // - Common failures (SECTION_FAILURE_COMMON); // - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ // transaction was sent but not executed within the deadline. diff --git a/proto-docs/container.md b/proto-docs/container.md index f8f994eb..446841af 100644 --- a/proto-docs/container.md +++ b/proto-docs/container.md @@ -86,7 +86,7 @@ set, server waits 15s after submitting the transaction. Statuses: - **OK** (0, SECTION_SUCCESS): \ - request to save the container has been sent to FS chain; + container successfully created;; - Common failures (SECTION_FAILURE_COMMON); - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ transaction was sent but not executed within the deadline. @@ -106,7 +106,7 @@ object would be also removed). Statuses: - **OK** (0, SECTION_SUCCESS): \ - request to remove the container has been sent to FS chain; + container successfully removed; - Common failures (SECTION_FAILURE_COMMON); - **CONTAINER_LOCKED** (3074, SECTION_CONTAINER): \ deleting a locked container is prohibited; @@ -151,7 +151,7 @@ not set, server waits 15s after submitting the transaction. Statuses: - **OK** (0, SECTION_SUCCESS): \ - request to save container eACL has been sent to FS chain; + container eACL successfully set; - Common failures (SECTION_FAILURE_COMMON); - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ transaction was sent but not executed within the deadline. From 146097b6c8dbf4c3a7b4c32a3a451f46f614493d Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 10 Dec 2025 14:15:01 +0300 Subject: [PATCH 2/2] container: Provide API for attribute management Closes #360. Signed-off-by: Leonard Lyubich --- CHANGELOG.md | 2 + container/service.proto | 163 ++++++++++++++++++++++++++++++++++ proto-docs/container.md | 190 ++++++++++++++++++++++++++++++++++++++++ proto-docs/session.md | 6 +- session/types.proto | 14 ++- 5 files changed, 373 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96d9e88e..5c12e026 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - Container `__NEOFS__LOCK_UNTIL` attribute (#357) - `CONTAINER_LOCKED` status (#357) - `CONTAINER_AWAIT_TIMEOUT` status (#358) +- `SetAttribute` and `RemoveAttribute` RPC to `ContainerService` (#362) +- `SETATTRIBUTE` and `REMOVEATTRIBUTE` verbs for container sessions V1 (#362) ### Changed - `ContainerService`'s `Put`, `Delete` and `SetExtendedACL` RPC are async/await now (#358) diff --git a/container/service.proto b/container/service.proto index 9fdc2001..5676d7c0 100644 --- a/container/service.proto +++ b/container/service.proto @@ -6,6 +6,7 @@ import "acl/types.proto"; import "container/types.proto"; import "refs/types.proto"; import "session/types.proto"; +import "status/types.proto"; option csharp_namespace = "Neo.FileStorage.API.Container"; option go_package = "github.com/nspcc-dev/neofs-sdk-go/proto/container"; @@ -100,6 +101,32 @@ service ContainerService { // DEPRECATED: every storage node must send storage load directly to `container` // contract. rpc AnnounceUsedSpace(AnnounceUsedSpaceRequest) returns (AnnounceUsedSpaceResponse); + + // Sends transaction calling contract method to set container attribute, and + // waits for the transaction to be executed. Deadline is determined by the + // transport protocol (e.g. `grpc-timeout` header). If the deadline is not + // set, server waits 15s after submitting the transaction. + // + // Statuses: + // - **OK** (0, SECTION_SUCCESS): \ + // attribute successfully set; + // - Common failures (SECTION_FAILURE_COMMON); + // - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ + // transaction was sent but not executed within the deadline. + rpc SetAttribute(SetAttributeRequest) returns (SetAttributeResponse); + + // Sends transaction calling contract method to remove container attribute, + // and waits for the transaction to be executed. Deadline is determined by + // the transport protocol (e.g. `grpc-timeout` header). If the deadline is + // not set, server waits 15s after submitting the transaction. + // + // Statuses: + // - **OK** (0, SECTION_SUCCESS): \ + // attribute successfully removed; + // - Common failures (SECTION_FAILURE_COMMON); + // - **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ + // transaction was sent but not executed within the deadline. + rpc RemoveAttribute(RemoveAttributeRequest) returns (RemoveAttributeResponse); } // New NeoFS Container creation request @@ -436,3 +463,139 @@ message AnnounceUsedSpaceResponse { // transmission. neo.fs.v2.session.ResponseVerificationHeader verify_header = 3; } + +// Attribute setting request +message SetAttributeRequest { + // Request payload message. + message Body { + // Op parameters message. + // + // If container does not have the `attribute`, it is added. Otherwise, its + // value is swapped. + // + // `attribute` must be one of: + // - `CORS`; + // - `__NEOFS__LOCK_UNTIL`. + // + // In general, requirements for `value` are the same as for container + // creation. Attribute-specific requirements: + // - `__NEOFS__LOCK_UNTIL`: new timestamp must be after the current one if any + message Parameters { + // Identifier of the container to set attribute for. + neo.fs.v2.refs.ContainerID container_id = 1; + + // Attribute to be set. + string attribute = 2; + + // New attribute value. + string value = 3; + } + + // Op parameters. + Parameters parameters = 1; + + // N3 witness of stable-marshalled `parameters` field. The + // signature must authenticate either container owner or one of subjects in + // the `session_token` field if any. Signature according to + // `ECDSA_RFC6979_SHA256` scheme is also supported. + neo.fs.v2.refs.SignatureRFC6979 signature = 2; + + // Optional session token. The token must be issued by the container owner. + // The token must have at least one subject authenticated by `signature` + // field. The token must have at least one context with this container and + // `CONTAINER_SETATTRIBUTE` verb. + neo.fs.v2.session.SessionTokenV2 session_token = 3; + + // Optional session token (V1). It must not be set together with + // `session_token` field that is highly recommended to be used instead. + // Requirements are the same for both. + neo.fs.v2.session.SessionToken session_token_v1 = 4; + } + + // Request payload. + Body body = 1; + + // Signature of stable-marshalled `body` field. + neo.fs.v2.refs.Signature body_signature = 2; +} + +// Attribute setting response +message SetAttributeResponse { + // Request result message. + message Body { + // Operation execution status. + neo.fs.v2.status.Status status = 1; + } + + // Request result. + Body body = 1; + + // Signature of stable-marshalled `body` field. + neo.fs.v2.refs.Signature body_signature = 2; +} + +// Attribute removal request +message RemoveAttributeRequest { + // Request payload message. + message Body { + // Op parameters message. + // + // If container does not have the `attribute`, nothing is done and status + // `OK` is returned. + // + // `attribute` must be one of: + // - `CORS`; + // - `__NEOFS__LOCK_UNTIL`. + // + // Attribute-specific requirements: + // - `__NEOFS__LOCK_UNTIL`: current timestamp must have already passed if any + message Parameters { + // Identifier of the container to remove attribute from. + neo.fs.v2.refs.ContainerID container_id = 1; + + // Attribute to be removed. + string attribute = 2; + } + + // Op parameters. + Parameters parameters = 1; + + // N3 witness of stable-marshalled `parameters` field. The + // signature must authenticate either container owner or one of subjects in + // the `session_token` field if any. Signature according to + // `ECDSA_RFC6979_SHA256` scheme is also supported. + neo.fs.v2.refs.SignatureRFC6979 signature = 2; + + // Optional session token. The token must be issued by the container owner. + // The token must have at least one subject authenticated by `signature` + // field. The token must have at least one context with this container and + // `CONTAINER_REMOVEATTRIBUTE` verb. + neo.fs.v2.session.SessionTokenV2 session_token = 3; + + // Optional session token (V1). It must not be set together with + // `session_token` field that is highly recommended to be used instead. + // Requirements are the same for both. + neo.fs.v2.session.SessionToken session_token_v1 = 4; + } + + // Request payload. + Body body = 1; + + // Signature of stable-marshalled `body` field. + neo.fs.v2.refs.Signature body_signature = 2; +} + +// Attribute removal response +message RemoveAttributeResponse { + // Request result message. + message Body { + // Operation execution status. + neo.fs.v2.status.Status status = 1; + } + + // Request result. + Body body = 1; + + // Signature of stable-marshalled `body` field. + neo.fs.v2.refs.Signature body_signature = 2; +} diff --git a/proto-docs/container.md b/proto-docs/container.md index 446841af..bc515357 100644 --- a/proto-docs/container.md +++ b/proto-docs/container.md @@ -33,6 +33,16 @@ - [PutRequest.Body](#neo.fs.v2.container.PutRequest.Body) - [PutResponse](#neo.fs.v2.container.PutResponse) - [PutResponse.Body](#neo.fs.v2.container.PutResponse.Body) + - [RemoveAttributeRequest](#neo.fs.v2.container.RemoveAttributeRequest) + - [RemoveAttributeRequest.Body](#neo.fs.v2.container.RemoveAttributeRequest.Body) + - [RemoveAttributeRequest.Body.Parameters](#neo.fs.v2.container.RemoveAttributeRequest.Body.Parameters) + - [RemoveAttributeResponse](#neo.fs.v2.container.RemoveAttributeResponse) + - [RemoveAttributeResponse.Body](#neo.fs.v2.container.RemoveAttributeResponse.Body) + - [SetAttributeRequest](#neo.fs.v2.container.SetAttributeRequest) + - [SetAttributeRequest.Body](#neo.fs.v2.container.SetAttributeRequest.Body) + - [SetAttributeRequest.Body.Parameters](#neo.fs.v2.container.SetAttributeRequest.Body.Parameters) + - [SetAttributeResponse](#neo.fs.v2.container.SetAttributeResponse) + - [SetAttributeResponse.Body](#neo.fs.v2.container.SetAttributeResponse.Body) - [SetExtendedACLRequest](#neo.fs.v2.container.SetExtendedACLRequest) - [SetExtendedACLRequest.Body](#neo.fs.v2.container.SetExtendedACLRequest.Body) - [SetExtendedACLResponse](#neo.fs.v2.container.SetExtendedACLResponse) @@ -74,6 +84,8 @@ rpc List(ListRequest) returns (ListResponse); rpc SetExtendedACL(SetExtendedACLRequest) returns (SetExtendedACLResponse); rpc GetExtendedACL(GetExtendedACLRequest) returns (GetExtendedACLResponse); rpc AnnounceUsedSpace(AnnounceUsedSpaceRequest) returns (AnnounceUsedSpaceResponse); +rpc SetAttribute(SetAttributeRequest) returns (SetAttributeResponse); +rpc RemoveAttribute(RemoveAttributeRequest) returns (RemoveAttributeResponse); ``` @@ -191,6 +203,40 @@ contract. | Name | Input | Output | | ---- | ----- | ------ | | AnnounceUsedSpace | [AnnounceUsedSpaceRequest](#neo.fs.v2.container.AnnounceUsedSpaceRequest) | [AnnounceUsedSpaceResponse](#neo.fs.v2.container.AnnounceUsedSpaceResponse) | +#### Method SetAttribute + +Sends transaction calling contract method to set container attribute, and +waits for the transaction to be executed. Deadline is determined by the +transport protocol (e.g. `grpc-timeout` header). If the deadline is not +set, server waits 15s after submitting the transaction. + +Statuses: +- **OK** (0, SECTION_SUCCESS): \ + attribute successfully set; +- Common failures (SECTION_FAILURE_COMMON); +- **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ + transaction was sent but not executed within the deadline. + +| Name | Input | Output | +| ---- | ----- | ------ | +| SetAttribute | [SetAttributeRequest](#neo.fs.v2.container.SetAttributeRequest) | [SetAttributeResponse](#neo.fs.v2.container.SetAttributeResponse) | +#### Method RemoveAttribute + +Sends transaction calling contract method to remove container attribute, +and waits for the transaction to be executed. Deadline is determined by +the transport protocol (e.g. `grpc-timeout` header). If the deadline is +not set, server waits 15s after submitting the transaction. + +Statuses: +- **OK** (0, SECTION_SUCCESS): \ + attribute successfully removed; +- Common failures (SECTION_FAILURE_COMMON); +- **CONTAINER_AWAIT_TIMEOUT** (3075, SECTION_CONTAINER): \ + transaction was sent but not executed within the deadline. + +| Name | Input | Output | +| ---- | ----- | ------ | +| RemoveAttribute | [RemoveAttributeRequest](#neo.fs.v2.container.RemoveAttributeRequest) | [RemoveAttributeResponse](#neo.fs.v2.container.RemoveAttributeResponse) | @@ -514,6 +560,150 @@ returned here to make sure everything has been done as expected. | container_id | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Unique identifier of the newly created container | + + +### Message RemoveAttributeRequest +Attribute removal request + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [RemoveAttributeRequest.Body](#neo.fs.v2.container.RemoveAttributeRequest.Body) | | Request payload. | +| body_signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of stable-marshalled `body` field. | + + + + +### Message RemoveAttributeRequest.Body +Request payload message. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| parameters | [RemoveAttributeRequest.Body.Parameters](#neo.fs.v2.container.RemoveAttributeRequest.Body.Parameters) | | Op parameters. | +| signature | [neo.fs.v2.refs.SignatureRFC6979](#neo.fs.v2.refs.SignatureRFC6979) | | N3 witness of stable-marshalled `parameters` field. The signature must authenticate either container owner or one of subjects in the `session_token` field if any. Signature according to `ECDSA_RFC6979_SHA256` scheme is also supported. | +| session_token | [neo.fs.v2.session.SessionTokenV2](#neo.fs.v2.session.SessionTokenV2) | | Optional session token. The token must be issued by the container owner. The token must have at least one subject authenticated by `signature` field. The token must have at least one context with this container and `CONTAINER_REMOVEATTRIBUTE` verb. | +| session_token_v1 | [neo.fs.v2.session.SessionToken](#neo.fs.v2.session.SessionToken) | | Optional session token (V1). It must not be set together with `session_token` field that is highly recommended to be used instead. Requirements are the same for both. | + + + + +### Message RemoveAttributeRequest.Body.Parameters +Op parameters message. + +If container does not have the `attribute`, nothing is done and status +`OK` is returned. + +`attribute` must be one of: + - `CORS`; + - `__NEOFS__LOCK_UNTIL`. + +Attribute-specific requirements: + - `__NEOFS__LOCK_UNTIL`: current timestamp must have already passed if any + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| container_id | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Identifier of the container to remove attribute from. | +| attribute | [string](#string) | | Attribute to be removed. | + + + + +### Message RemoveAttributeResponse +Attribute removal response + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [RemoveAttributeResponse.Body](#neo.fs.v2.container.RemoveAttributeResponse.Body) | | Request result. | +| body_signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of stable-marshalled `body` field. | + + + + +### Message RemoveAttributeResponse.Body +Request result message. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| status | [neo.fs.v2.status.Status](#neo.fs.v2.status.Status) | | Operation execution status. | + + + + +### Message SetAttributeRequest +Attribute setting request + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [SetAttributeRequest.Body](#neo.fs.v2.container.SetAttributeRequest.Body) | | Request payload. | +| body_signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of stable-marshalled `body` field. | + + + + +### Message SetAttributeRequest.Body +Request payload message. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| parameters | [SetAttributeRequest.Body.Parameters](#neo.fs.v2.container.SetAttributeRequest.Body.Parameters) | | Op parameters. | +| signature | [neo.fs.v2.refs.SignatureRFC6979](#neo.fs.v2.refs.SignatureRFC6979) | | N3 witness of stable-marshalled `parameters` field. The signature must authenticate either container owner or one of subjects in the `session_token` field if any. Signature according to `ECDSA_RFC6979_SHA256` scheme is also supported. | +| session_token | [neo.fs.v2.session.SessionTokenV2](#neo.fs.v2.session.SessionTokenV2) | | Optional session token. The token must be issued by the container owner. The token must have at least one subject authenticated by `signature` field. The token must have at least one context with this container and `CONTAINER_SETATTRIBUTE` verb. | +| session_token_v1 | [neo.fs.v2.session.SessionToken](#neo.fs.v2.session.SessionToken) | | Optional session token (V1). It must not be set together with `session_token` field that is highly recommended to be used instead. Requirements are the same for both. | + + + + +### Message SetAttributeRequest.Body.Parameters +Op parameters message. + +If container does not have the `attribute`, it is added. Otherwise, its +value is swapped. + +`attribute` must be one of: + - `CORS`; + - `__NEOFS__LOCK_UNTIL`. + +In general, requirements for `value` are the same as for container +creation. Attribute-specific requirements: + - `__NEOFS__LOCK_UNTIL`: new timestamp must be after the current one if any + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| container_id | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Identifier of the container to set attribute for. | +| attribute | [string](#string) | | Attribute to be set. | +| value | [string](#string) | | New attribute value. | + + + + +### Message SetAttributeResponse +Attribute setting response + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| body | [SetAttributeResponse.Body](#neo.fs.v2.container.SetAttributeResponse.Body) | | Request result. | +| body_signature | [neo.fs.v2.refs.Signature](#neo.fs.v2.refs.Signature) | | Signature of stable-marshalled `body` field. | + + + + +### Message SetAttributeResponse.Body +Request result message. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| status | [neo.fs.v2.status.Status](#neo.fs.v2.status.Status) | | Operation execution status. | + + ### Message SetExtendedACLRequest diff --git a/proto-docs/session.md b/proto-docs/session.md index 5e3a88df..70ed0fa7 100644 --- a/proto-docs/session.md +++ b/proto-docs/session.md @@ -250,7 +250,7 @@ SessionContextV2 carries unified context for both ObjectService and ContainerSer | ----- | ---- | ----- | ----------- | | container | [neo.fs.v2.refs.ContainerID](#neo.fs.v2.refs.ContainerID) | | Container where operation is allowed. For container operations, this is the container being operated on. For object operations, this is the container holding the objects. | | objects | [neo.fs.v2.refs.ObjectID](#neo.fs.v2.refs.ObjectID) | repeated | Specific objects where operation is allowed. Only relevant for object operations. Empty list means all objects in the container. Maximum number of objects: 1000. | -| verbs | [Verb](#neo.fs.v2.session.Verb) | repeated | Operations authorized for this context. Maximum number of verbs: 10. | +| verbs | [Verb](#neo.fs.v2.session.Verb) | repeated | Operations authorized for this context. Maximum number of verbs: 12. | @@ -393,6 +393,8 @@ Container request verbs | PUT | 1 | Refers to container.Put RPC call | | DELETE | 2 | Refers to container.Delete RPC call | | SETEACL | 3 | Refers to container.SetExtendedACL RPC call | +| SETATTRIBUTE | 4 | Refers to container.SetAttribute RPC call | +| REMOVEATTRIBUTE | 5 | Refers to container.RemoveAttribute RPC call | @@ -434,6 +436,8 @@ container service operations. | CONTAINER_PUT | 8 | Refers to container.Put RPC call | | CONTAINER_DELETE | 9 | Refers to container.Delete RPC call | | CONTAINER_SETEACL | 10 | Refers to container.SetExtendedACL RPC call | +| CONTAINER_SETATTRIBUTE | 11 | Refers to container.SetAttribute RPC call | +| CONTAINER_REMOVEATTRIBUTE | 12 | Refers to container.RemoveAttribute RPC call | diff --git a/session/types.proto b/session/types.proto index b1a69a91..18fe03cc 100644 --- a/session/types.proto +++ b/session/types.proto @@ -49,6 +49,12 @@ enum Verb { // Refers to container.SetExtendedACL RPC call CONTAINER_SETEACL = 10; + + // Refers to container.SetAttribute RPC call + CONTAINER_SETATTRIBUTE = 11; + + // Refers to container.RemoveAttribute RPC call + CONTAINER_REMOVEATTRIBUTE = 12; } // Context information for Session Tokens related to ObjectService requests @@ -114,6 +120,12 @@ message ContainerSessionContext { // Refers to container.SetExtendedACL RPC call SETEACL = 3; + + // Refers to container.SetAttribute RPC call + SETATTRIBUTE = 4; + + // Refers to container.RemoveAttribute RPC call + REMOVEATTRIBUTE = 5; } // Type of request for which the token is issued Verb verb = 1 [json_name = "verb"]; @@ -325,7 +337,7 @@ message SessionContextV2 { repeated neo.fs.v2.refs.ObjectID objects = 2 [json_name = "objects"]; // Operations authorized for this context. - // Maximum number of verbs: 10. + // Maximum number of verbs: 12. repeated Verb verbs = 3 [json_name = "verbs"]; }