Skip to content

Commit fc63648

Browse files
authored
Storage policy limits (#3174)
2 parents a57ef2d + 4e591b9 commit fc63648

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Changelog for NeoFS Node
3939
- More efficient block header subscription is used now instead of block-based one (#3163)
4040
- `ObjectService.GetRange(Hash)` ops now handle zero ranges as full payload (#3071)
4141
- Add some GAS to system fee of notary transactions (#3176)
42+
- IR now applies sane limits to containers' storage policies recently added to the protocol (#3075)
4243

4344
### Removed
4445
- Drop creating new eacl tables with public keys (#3096)

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ require (
1919
github.com/nspcc-dev/neo-go v0.108.0
2020
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea
2121
github.com/nspcc-dev/neofs-contract v0.21.0
22-
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250224145523-bf4a81ef7d79
22+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250225182134-37f733e9af21
2323
github.com/nspcc-dev/tzhash v1.8.2
2424
github.com/olekukonko/tablewriter v0.0.5
2525
github.com/panjf2000/ants/v2 v2.9.0

go.sum

+2-1
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,9 @@ github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea h1:mK
190190
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240827150555-5ce597aa14ea/go.mod h1:YzhD4EZmC9Z/PNyd7ysC7WXgIgURc9uCG1UWDeV027Y=
191191
github.com/nspcc-dev/neofs-contract v0.21.0 h1:dJkrZr7C8ngMiShwdUl27nbLCGez1KD7W1l7RRXFoN8=
192192
github.com/nspcc-dev/neofs-contract v0.21.0/go.mod h1:TKR2DJiZCdzq9CPljI101c9S3uK5CsVK5WQrX4C+Y7A=
193-
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250224145523-bf4a81ef7d79 h1:iJYbi1e7rx1Ga6fjcwH4bQMjuR/cD0VGeTM8wmqmjuM=
194193
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250224145523-bf4a81ef7d79/go.mod h1:Hd0zRo7mfGDf/S+yGPnRi9eWipxJNhec2Oik1w7lwQo=
194+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250225182134-37f733e9af21 h1:TFGaR7uCgV4RMY6htwvMFYZSVnumyhaUbuuV6BzWmew=
195+
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12.0.20250225182134-37f733e9af21/go.mod h1:Hd0zRo7mfGDf/S+yGPnRi9eWipxJNhec2Oik1w7lwQo=
195196
github.com/nspcc-dev/rfc6979 v0.2.3 h1:QNVykGZ3XjFwM/88rGfV3oj4rKNBy+nYI6jM7q19hDI=
196197
github.com/nspcc-dev/rfc6979 v0.2.3/go.mod h1:q3sCL1Ed7homjqYK8KmFSzEmm+7Ngyo7PePbZanhaDE=
197198
github.com/nspcc-dev/tzhash v1.8.2 h1:ebRCbPoEuoqrhC6sSZmrT/jI3h1SzCWakxxV6gp5QAg=

pkg/innerring/processors/container/process_container.go

+4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
106106
return fmt.Errorf("auth container creation: %w", err)
107107
}
108108

109+
if err = ctx.cnr.PlacementPolicy().Verify(); err != nil {
110+
return fmt.Errorf("invalid storage policy: %w", err)
111+
}
112+
109113
// check homomorphic hashing setting
110114
err = checkHomomorphicHashing(cp.netState, ctx.cnr)
111115
if err != nil {

pkg/services/container/server.go

+57
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"crypto/ecdsa"
66
"errors"
77
"fmt"
8+
"slices"
89

910
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
1011
"github.com/nspcc-dev/neofs-node/pkg/services/util"
@@ -15,6 +16,7 @@ import (
1516
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
1617
"github.com/nspcc-dev/neofs-sdk-go/eacl"
1718
protocontainer "github.com/nspcc-dev/neofs-sdk-go/proto/container"
19+
protonetmap "github.com/nspcc-dev/neofs-sdk-go/proto/netmap"
1820
"github.com/nspcc-dev/neofs-sdk-go/proto/refs"
1921
protosession "github.com/nspcc-dev/neofs-sdk-go/proto/session"
2022
protostatus "github.com/nspcc-dev/neofs-sdk-go/proto/status"
@@ -182,6 +184,54 @@ func (s *server) makeFailedPutResponse(err error) (*protocontainer.PutResponse,
182184
return s.makePutResponse(nil, util.ToStatus(err))
183185
}
184186

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+
185235
// Put forwards container creation request to the underlying [Contract] for
186236
// further processing. If session token is attached, it's verified. Returns ID
187237
// to check request status in the response.
@@ -200,6 +250,13 @@ func (s *server) Put(_ context.Context, req *protocontainer.PutRequest) (*protoc
200250
return s.makeFailedPutResponse(errors.New("missing container"))
201251
}
202252

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+
203260
var cnr container.Container
204261
if err := cnr.FromProtoMessage(mCnr); err != nil {
205262
return s.makeFailedPutResponse(fmt.Errorf("invalid container: %w", err))

0 commit comments

Comments
 (0)