5
5
"crypto/ecdsa"
6
6
"errors"
7
7
"fmt"
8
+ "slices"
8
9
9
10
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
10
11
"github.com/nspcc-dev/neofs-node/pkg/services/util"
@@ -15,6 +16,7 @@ import (
15
16
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
16
17
"github.com/nspcc-dev/neofs-sdk-go/eacl"
17
18
protocontainer "github.com/nspcc-dev/neofs-sdk-go/proto/container"
19
+ protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap"
18
20
"github.com/nspcc-dev/neofs-sdk-go/proto/refs"
19
21
protosession "github.com/nspcc-dev/neofs-sdk-go/proto/session"
20
22
protostatus "github.com/nspcc-dev/neofs-sdk-go/proto/status"
@@ -182,6 +184,54 @@ func (s *server) makeFailedPutResponse(err error) (*protocontainer.PutResponse,
182
184
return s .makePutResponse (nil , util .ToStatus (err ))
183
185
}
184
186
187
+ const (
188
+ maxObjectReplicasPerSet = 8
189
+ maxContainerNodesInSet = 64
190
+ maxContainerNodeSets = 256
191
+ maxContainerNodes = 512
192
+ )
193
+
194
+ const defaultBackupFactor = 3
195
+
196
+ var errInvalidNodeSetDesc = errors .New ("invalid node set descriptor" )
197
+
198
+ func verifyStoragePolicy (policy * protonetmap.PlacementPolicy ) error {
199
+ if len (policy .Replicas ) > maxContainerNodeSets {
200
+ return fmt .Errorf ("more than %d node sets" , maxContainerNodeSets )
201
+ }
202
+ bf := policy .ContainerBackupFactor
203
+ if bf == 0 {
204
+ bf = defaultBackupFactor
205
+ }
206
+ var cnrNodeCount uint32
207
+ for i := range policy .Replicas {
208
+ if policy .Replicas [i ] == nil {
209
+ return fmt .Errorf ("nil replica #%d" , i )
210
+ }
211
+ if policy .Replicas [i ].Count > maxObjectReplicasPerSet {
212
+ return fmt .Errorf ("%w #%d: more than %d object replicas" , errInvalidNodeSetDesc , i , maxObjectReplicasPerSet )
213
+ }
214
+ var sNum uint32
215
+ if policy .Replicas [i ].Selector != "" {
216
+ si := slices .IndexFunc (policy .Selectors , func (s * protonetmap.Selector ) bool { return s != nil && s .Name == policy .Replicas [i ].Selector })
217
+ if si < 0 {
218
+ return fmt .Errorf ("%w #%d: missing selector %q" , errInvalidNodeSetDesc , i , policy .Replicas [i ].Selector )
219
+ }
220
+ sNum = policy .Selectors [si ].Count
221
+ } else {
222
+ sNum = policy .Replicas [i ].Count
223
+ }
224
+ nodesInSet := bf * sNum
225
+ if nodesInSet > maxContainerNodesInSet {
226
+ return fmt .Errorf ("%w #%d: more than %d nodes" , errInvalidNodeSetDesc , i , maxContainerNodesInSet )
227
+ }
228
+ if cnrNodeCount += nodesInSet ; cnrNodeCount > maxContainerNodes {
229
+ return fmt .Errorf ("more than %d nodes in total" , maxContainerNodes )
230
+ }
231
+ }
232
+ return nil
233
+ }
234
+
185
235
// Put forwards container creation request to the underlying [Contract] for
186
236
// further processing. If session token is attached, it's verified. Returns ID
187
237
// to check request status in the response.
@@ -200,6 +250,13 @@ func (s *server) Put(_ context.Context, req *protocontainer.PutRequest) (*protoc
200
250
return s .makeFailedPutResponse (errors .New ("missing container" ))
201
251
}
202
252
253
+ if mCnr .PlacementPolicy == nil {
254
+ return s .makeFailedPutResponse (errors .New ("missing storage policy" ))
255
+ }
256
+ if err := verifyStoragePolicy (mCnr .PlacementPolicy ); err != nil {
257
+ return s .makeFailedPutResponse (fmt .Errorf ("invalid storage policy: %w" , err ))
258
+ }
259
+
203
260
var cnr container.Container
204
261
if err := cnr .FromProtoMessage (mCnr ); err != nil {
205
262
return s .makeFailedPutResponse (fmt .Errorf ("invalid container: %w" , err ))
0 commit comments