Skip to content

Commit 5744113

Browse files
Synchronous container operations (#3711)
2 parents af84826 + d73cb1c commit 5744113

File tree

13 files changed

+223
-145
lines changed

13 files changed

+223
-145
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Changelog for NeoFS Node
99
- IR structures containers in the contract iteratively (#3670)
1010
- SN tries new NEP-11 methods `tokens` and `tokensOf` of Container contract (#3701)
1111
- SN now listens to NEP-11 `transfer` events of Container contract (#3701)
12+
- CLI supports `CONTAINER_AWAIT_TIMEOUT` status now (#3711)
1213

1314
### Fixed
1415
- IR panics at graceful shutdown (#3706)
@@ -17,11 +18,13 @@ Changelog for NeoFS Node
1718
### Changed
1819
- Optimized locking info in metabase (#3672)
1920
- Lock objects with API <2.18 are no longer accepted (#3672)
21+
- SN handles `ContainerService`'s `Put`, `Delete` and `SetExtendedACL` requests in sync manner (#3711)
2022

2123
### Removed
2224

2325
### Updated
2426
- `github.com/nspcc-dev/neofs-contract` module to `v0.25.2-0.20251124180339-40ec608b4893` (#3670)
27+
- `github.com/nspcc-dev/neofs-sdk-go` module to `v1.0.0-rc.16.0.20251203135706-86667929fbb8` (#3711)
2528

2629
### Updating from v0.50.2
2730

cmd/neofs-cli/modules/container/create.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/commonflags"
1313
"github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/key"
1414
"github.com/nspcc-dev/neofs-sdk-go/client"
15+
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
1516
"github.com/nspcc-dev/neofs-sdk-go/container"
1617
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
1718
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
@@ -147,6 +148,9 @@ It will be stored in FS chain when inner ring will accepts it.`,
147148

148149
id, err := actor.ContainerPut(ctx, cnr, user.NewAutoIDSignerRFC6979(*key), putPrm)
149150
if err != nil {
151+
if errors.Is(err, apistatus.ErrContainerAwaitTimeout) {
152+
err = waiter.ErrConfirmationTimeout
153+
}
150154
return fmt.Errorf("put container rpc error: %w", err)
151155
}
152156

cmd/neofs-node/container.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ package main
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"fmt"
78
"slices"
89
"sync"
910
"time"
1011

1112
containerCore "github.com/nspcc-dev/neofs-node/pkg/core/container"
13+
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
1214
balanceClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
1315
cntClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
1416
"github.com/nspcc-dev/neofs-node/pkg/morph/event"
@@ -526,7 +528,7 @@ func (x *containersInChain) List(id user.ID) ([]cid.ID, error) {
526528
return x.cnrLst.List(&id)
527529
}
528530

529-
func (x *containersInChain) Put(cnr containerSDK.Container, pub, sig []byte, st *session.Container) (cid.ID, error) {
531+
func (x *containersInChain) Put(ctx context.Context, cnr containerSDK.Container, pub, sig []byte, st *session.Container) (cid.ID, error) {
530532
var prm cntClient.PutPrm
531533
prm.SetContainer(cnr)
532534
prm.SetKey(pub)
@@ -535,35 +537,46 @@ func (x *containersInChain) Put(cnr containerSDK.Container, pub, sig []byte, st
535537
prm.SetToken(st.Marshal())
536538
}
537539

538-
return x.cCli.Put(prm)
540+
id, err := x.cCli.Put(ctx, prm)
541+
if errors.Is(err, client.ErrTxAwaitTimeout) {
542+
err = apistatus.ErrContainerAwaitTimeout
543+
}
544+
545+
return id, err
539546
}
540547

541-
func (x *containersInChain) Delete(id cid.ID, pub, sig []byte, st *session.Container) error {
548+
func (x *containersInChain) Delete(ctx context.Context, id cid.ID, pub, sig []byte, st *session.Container) error {
542549
var prm cntClient.DeletePrm
543550
prm.SetCID(id[:])
544551
prm.SetSignature(sig)
545552
prm.SetKey(pub)
546-
prm.RequireAlphabetSignature()
547553
if st != nil {
548554
prm.SetToken(st.Marshal())
549555
}
550-
return x.cCli.Delete(prm)
556+
557+
err := x.cCli.Delete(ctx, prm)
558+
if errors.Is(err, client.ErrTxAwaitTimeout) {
559+
err = apistatus.ErrContainerAwaitTimeout
560+
}
561+
562+
return err
551563
}
552564

553-
func (x *containersInChain) PutEACL(eACL eacl.Table, pub, sig []byte, st *session.Container) error {
565+
func (x *containersInChain) PutEACL(ctx context.Context, eACL eacl.Table, pub, sig []byte, st *session.Container) error {
554566
var prm cntClient.PutEACLPrm
555567
prm.SetTable(eACL.Marshal())
556568
prm.SetKey(pub)
557569
prm.SetSignature(sig)
558-
prm.RequireAlphabetSignature()
559570
if st != nil {
560571
prm.SetToken(st.Marshal())
561572
}
562-
if err := x.cCli.PutEACL(prm); err != nil {
563-
return err
573+
574+
err := x.cCli.PutEACL(ctx, prm)
575+
if errors.Is(err, client.ErrTxAwaitTimeout) {
576+
err = apistatus.ErrContainerAwaitTimeout
564577
}
565578

566-
return nil
579+
return err
567580
}
568581

569582
type containerPresenceChecker struct{ src containerCore.Source }

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ require (
2222
github.com/nspcc-dev/neo-go v0.114.0
2323
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea
2424
github.com/nspcc-dev/neofs-contract v0.25.2-0.20251124180339-40ec608b4893
25-
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251118154818-9480da80f9ad
25+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251203135706-86667929fbb8
2626
github.com/nspcc-dev/tzhash v1.8.3
2727
github.com/panjf2000/ants/v2 v2.11.3
2828
github.com/prometheus/client_golang v1.23.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK
199199
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y=
200200
github.com/nspcc-dev/neofs-contract v0.25.2-0.20251124180339-40ec608b4893 h1:sh25Y5GMLL9ixlcJdbktHkFUY3nyK9DeLY5EBaEQDwQ=
201201
github.com/nspcc-dev/neofs-contract v0.25.2-0.20251124180339-40ec608b4893/go.mod h1:CYX51uP2pNBCK7Q0ygD1LNsoFSHbB2F5luaBrluFkUo=
202-
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251118154818-9480da80f9ad h1:hWJBAWUqGHqvtInPljzfGP2TIDdMA+jYMX5/DCCyJjA=
203-
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251118154818-9480da80f9ad/go.mod h1:MbgvTuiYY3uG+iMqIcvojmNHfZcxGNz4U+EKNBKPHzE=
202+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251203135706-86667929fbb8 h1:oasL8SD11yOmW0a/GqMmm4/0sb86hMOYMi7HC20PIb0=
203+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.16.0.20251203135706-86667929fbb8/go.mod h1:IrM1JG/klBtecZEApIf8USgLonNcarv32R1O0dj4kQI=
204204
github.com/nspcc-dev/rfc6979 v0.2.4 h1:NBgsdCjhLpEPJZqmC9rciMZDcSY297po2smeaRjw57k=
205205
github.com/nspcc-dev/rfc6979 v0.2.4/go.mod h1:86ylDw6Kss+P6v4QAJqo1Sp3mC0/Zr9G97xSjQ9TuFg=
206206
github.com/nspcc-dev/tzhash v1.8.3 h1:EWJMOL/ppdqNBvkKjHECljusopcsNu4i4kH8KctTv10=

pkg/morph/client/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
2424
"github.com/nspcc-dev/neo-go/pkg/rpcclient/rolemgmt"
2525
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
26+
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
2627
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
2728
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
2829
"github.com/nspcc-dev/neo-go/pkg/util"
@@ -32,6 +33,9 @@ import (
3233
"go.uber.org/zap"
3334
)
3435

36+
// ErrTxAwaitTimeout is returned when transaction awaiting timed out.
37+
var ErrTxAwaitTimeout = waiter.ErrContextDone
38+
3539
// Client is a wrapper over web socket neo-go client
3640
// that provides smart-contract invocation interface
3741
// and notification subscription functionality.

pkg/morph/client/container/delete.go

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package container
22

33
import (
4+
"context"
45
"fmt"
56

6-
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
77
fschaincontracts "github.com/nspcc-dev/neofs-node/pkg/morph/contracts"
88
)
99

@@ -13,8 +13,6 @@ type DeletePrm struct {
1313
signature []byte
1414
key []byte
1515
token []byte
16-
17-
client.InvokePrmOptional
1816
}
1917

2018
// SetCID sets container ID.
@@ -37,32 +35,27 @@ func (d *DeletePrm) SetToken(token []byte) {
3735
d.token = token
3836
}
3937

40-
// Delete removes the container from NeoFS system
41-
// through Container contract call.
38+
// Delete calls Container contract to delete container with parameterized
39+
// credentials. If transaction is accepted for processing, Delete waits for it
40+
// to be successfully executed. Waiting is performed within ctx,
41+
// [client.ErrTxAwaitTimeout] is returned when it is done.
4242
//
4343
// Returns any error encountered that caused
4444
// the removal to interrupt.
45-
func (c *Client) Delete(p DeletePrm) error {
45+
func (c *Client) Delete(ctx context.Context, p DeletePrm) error {
4646
if len(p.signature) == 0 {
4747
return errNilArgument
4848
}
4949

50-
prm := client.InvokePrm{}
51-
prm.SetMethod(fschaincontracts.RemoveContainerMethod)
52-
prm.SetArgs(p.cnr, p.signature, p.key, p.token)
53-
prm.InvokePrmOptional = p.InvokePrmOptional
54-
55-
// no magic bugs with notary requests anymore, this operation should
56-
// _always_ be notary signed so make it one more time even if it is
57-
// a repeated flag setting
58-
prm.RequireAlphabetSignature()
59-
60-
err := c.client.Invoke(prm)
50+
err := c.client.CallWithAlphabetWitness(ctx, fschaincontracts.RemoveContainerMethod, []any{
51+
p.cnr, p.signature, p.key, p.token,
52+
})
6153
if err != nil {
6254
if isMethodNotFoundError(err, fschaincontracts.RemoveContainerMethod) {
63-
prm.SetMethod(deleteMethod)
64-
prm.SetArgs(p.cnr, p.signature, p.token)
65-
if err = c.client.Invoke(prm); err != nil {
55+
err = c.client.CallWithAlphabetWitness(ctx, deleteMethod, []any{
56+
p.cnr, p.signature, p.key, p.token,
57+
})
58+
if err != nil {
6659
return fmt.Errorf("could not invoke method (%s): %w", deleteMethod, err)
6760
}
6861
return nil

pkg/morph/client/container/eacl_set.go

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package container
22

33
import (
4+
"context"
45
"fmt"
56

6-
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
77
fschaincontracts "github.com/nspcc-dev/neofs-node/pkg/morph/contracts"
88
)
99

@@ -13,8 +13,6 @@ type PutEACLPrm struct {
1313
key []byte
1414
sig []byte
1515
token []byte
16-
17-
client.InvokePrmOptional
1816
}
1917

2018
// SetTable sets table.
@@ -37,30 +35,26 @@ func (p *PutEACLPrm) SetToken(token []byte) {
3735
p.token = token
3836
}
3937

40-
// PutEACL saves binary eACL table with its session token, key and signature
41-
// in NeoFS system through Container contract call.
38+
// PutEACL calls Container contract to set container's extended ACL with
39+
// parameterized credentials. If transaction is accepted for processing, PutEACL
40+
// waits for it to be successfully executed. Waiting is done within ctx,
41+
// [client.ErrTxAwaitTimeout] is returned when it is done.
4242
//
4343
// Returns any error encountered that caused the saving to interrupt.
44-
func (c *Client) PutEACL(p PutEACLPrm) error {
44+
func (c *Client) PutEACL(ctx context.Context, p PutEACLPrm) error {
4545
if len(p.sig) == 0 || len(p.key) == 0 {
4646
return errNilArgument
4747
}
4848

49-
prm := client.InvokePrm{}
50-
prm.SetMethod(fschaincontracts.PutContainerEACLMethod)
51-
prm.SetArgs(p.table, p.sig, p.key, p.token)
52-
prm.InvokePrmOptional = p.InvokePrmOptional
53-
54-
// no magic bugs with notary requests anymore, this operation should
55-
// _always_ be notary signed so make it one more time even if it is
56-
// a repeated flag setting
57-
prm.RequireAlphabetSignature()
58-
59-
err := c.client.Invoke(prm)
49+
err := c.client.CallWithAlphabetWitness(ctx, fschaincontracts.PutContainerEACLMethod, []any{
50+
p.table, p.sig, p.key, p.token,
51+
})
6052
if err != nil {
6153
if isMethodNotFoundError(err, fschaincontracts.PutContainerEACLMethod) {
62-
prm.SetMethod(setEACLMethod)
63-
if err = c.client.Invoke(prm); err != nil {
54+
err = c.client.CallWithAlphabetWitness(ctx, setEACLMethod, []any{
55+
p.table, p.sig, p.key, p.token,
56+
})
57+
if err != nil {
6458
return fmt.Errorf("could not invoke method (%s): %w", setEACLMethod, err)
6559
}
6660
return nil

pkg/morph/client/container/put.go

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package container
22

33
import (
4+
"context"
45
"fmt"
56

6-
"github.com/nspcc-dev/neofs-node/pkg/morph/client"
77
fschaincontracts "github.com/nspcc-dev/neofs-node/pkg/morph/contracts"
88
"github.com/nspcc-dev/neofs-sdk-go/container"
99
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
@@ -15,8 +15,6 @@ type PutPrm struct {
1515
key []byte
1616
sig []byte
1717
token []byte
18-
19-
client.InvokePrmOptional
2018
}
2119

2220
// SetContainer sets container.
@@ -39,47 +37,42 @@ func (p *PutPrm) SetToken(token []byte) {
3937
p.token = token
4038
}
4139

42-
// Put saves container with its session token, key and signature
43-
// in NeoFS system through Container contract call.
40+
// Put calls Container contract to create container with parameterized
41+
// credentials. If transaction is accepted for processing, Put waits for it to
42+
// be successfully executed. Waiting is performed within ctx,
43+
// [client.ErrTxAwaitTimeout] is returned when it is done.
4444
//
4545
// Returns calculated container identifier and any error
4646
// encountered that caused the saving to interrupt.
47-
func (c *Client) Put(p PutPrm) (cid.ID, error) {
47+
func (c *Client) Put(ctx context.Context, p PutPrm) (cid.ID, error) {
4848
if len(p.sig) == 0 || len(p.key) == 0 {
4949
return cid.ID{}, errNilArgument
5050
}
5151

52-
var prm client.InvokePrm
53-
prm.SetMethod(fschaincontracts.CreateContainerV2Method)
54-
prm.InvokePrmOptional = p.InvokePrmOptional
55-
prm.SetArgs(containerToStackItem(p.cnr), p.sig, p.key, p.token)
56-
57-
// no magic bugs with notary requests anymore, this operation should
58-
// _always_ be notary signed so make it one more time even if it is
59-
// a repeated flag setting
60-
prm.RequireAlphabetSignature()
61-
62-
err := c.client.Invoke(prm)
52+
err := c.client.CallWithAlphabetWitness(ctx, fschaincontracts.CreateContainerV2Method, []any{
53+
containerToStackItem(p.cnr), p.sig, p.key, p.token,
54+
})
6355
if err == nil {
6456
return cid.NewFromMarshalledContainer(p.cnr.Marshal()), nil
6557
}
6658
if !isMethodNotFoundError(err, fschaincontracts.CreateContainerV2Method) {
6759
return cid.ID{}, fmt.Errorf("could not invoke method (%s): %w", fschaincontracts.CreateContainerV2Method, err)
6860
}
6961

70-
prm.SetMethod(fschaincontracts.CreateContainerMethod)
71-
7262
domain := p.cnr.ReadDomain()
7363
metaAttr := p.cnr.Attribute("__NEOFS__METAINFO_CONSISTENCY")
7464
metaEnabled := metaAttr == "optimistic" || metaAttr == "strict"
7565
cnrBytes := p.cnr.Marshal()
76-
prm.SetArgs(cnrBytes, p.sig, p.key, p.token, domain.Name(), domain.Zone(), metaEnabled)
7766

78-
err = c.client.Invoke(prm)
67+
err = c.client.CallWithAlphabetWitness(ctx, fschaincontracts.CreateContainerMethod, []any{
68+
cnrBytes, p.sig, p.key, p.token, domain.Name(), domain.Zone(), metaEnabled,
69+
})
7970
if err != nil {
8071
if isMethodNotFoundError(err, fschaincontracts.CreateContainerMethod) {
81-
prm.SetMethod(putMethod)
82-
if err = c.client.Invoke(prm); err != nil {
72+
err = c.client.CallWithAlphabetWitness(ctx, putMethod, []any{
73+
cnrBytes, p.sig, p.key, p.token, domain.Name(), domain.Zone(), metaEnabled,
74+
})
75+
if err != nil {
8376
return cid.ID{}, fmt.Errorf("could not invoke method (%s): %w", putMethod, err)
8477
}
8578
return cid.NewFromMarshalledContainer(cnrBytes), nil

0 commit comments

Comments
 (0)