diff --git a/CHANGELOG.md b/CHANGELOG.md index 921fdc2168..a4cbaeb812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ Changelog for NeoFS Node - Compressed object format support from FSTree (#4223) - Deprecated homomorphic hashing setting from CLI netinfo output (#4225) - Support for multiaddr addresses in CLI and node (#4238) +- Support for `create` method of Container contract in IR (#4242) +- Support for `Created` and `Removed` events of Container contract in SN (#4242) ### Updated - `github.com/nspcc-dev/neofs-sdk-go` module to `v1.0.0-rc.23.0.20261021092246-abe302e8498b` (#4194, #4219, #4228, #4224, #4222, #4240) diff --git a/cmd/neofs-node/container.go b/cmd/neofs-node/container.go index 5eb97efbf8..686db4fe42 100644 --- a/cmd/neofs-node/container.go +++ b/cmd/neofs-node/container.go @@ -331,12 +331,6 @@ func registerEventParserOnceContainer(c *cfg, name string, p event.NotificationP // NOT be called concurrently with itself and other similar functions. Owner may // be zero. func subscribeToContainerCreation(c *cfg, h func(id cid.ID, owner user.ID)) { - const eventNameContainerCreatedV2 = "Created" - registerEventParserOnceContainer(c, eventNameContainerCreatedV2, containerEvent.RestoreCreated) - addContainerAsyncNotificationHandler(c, eventNameContainerCreatedV2, func(e event.Event) { - created := e.(containerEvent.Created) - h(created.ID, created.Owner) - }) subscribeToContainerTransfer(c, func(id cid.ID, from, to user.ID) { if from.IsZero() { h(id, to) @@ -346,12 +340,6 @@ func subscribeToContainerCreation(c *cfg, h func(id cid.ID, owner user.ID)) { // like subscribeToContainerCreation but for removal. Owner may be zero. func subscribeToContainerRemoval(c *cfg, h func(id cid.ID, owner user.ID)) { - const eventNameContainerRemovedV2 = "Removed" - registerEventParserOnceContainer(c, eventNameContainerRemovedV2, containerEvent.RestoreRemoved) - addContainerAsyncNotificationHandler(c, eventNameContainerRemovedV2, func(e event.Event) { - removed := e.(containerEvent.Removed) - h(removed.ID, removed.Owner) - }) subscribeToContainerTransfer(c, func(id cid.ID, from, to user.ID) { if to.IsZero() { h(id, from) diff --git a/pkg/innerring/processors/container/handlers.go b/pkg/innerring/processors/container/handlers.go index 20b03b8195..2e840460df 100644 --- a/pkg/innerring/processors/container/handlers.go +++ b/pkg/innerring/processors/container/handlers.go @@ -1,7 +1,6 @@ package container import ( - "crypto/sha256" "encoding/hex" "github.com/mr-tron/base58" @@ -20,24 +19,6 @@ func (cp *Processor) handleCreationRequest(ev event.Event) { } } -func (cp *Processor) handlePut(ev event.Event) { - req := ev.(containerEvent.CreateContainerRequest) - - id := sha256.Sum256(req.Container) - cp.log.Info("notification", - zap.String("type", "container put"), - zap.String("id", base58.Encode(id[:]))) - - // send an event to the worker pool - - err := cp.pool.Submit(func() { cp.processContainerPut(req, id) }) - if err != nil { - // there system can be moved into controlled degradation stage - cp.log.Warn("container processor worker pool drained", - zap.Int("capacity", cp.pool.Cap())) - } -} - func (cp *Processor) handleDelete(ev event.Event) { req := ev.(containerEvent.RemoveContainerRequest) if req.VerificationScript == nil { diff --git a/pkg/innerring/processors/container/process_container.go b/pkg/innerring/processors/container/process_container.go index 1e962047c3..4d2f4d2ddc 100644 --- a/pkg/innerring/processors/container/process_container.go +++ b/pkg/innerring/processors/container/process_container.go @@ -36,7 +36,7 @@ func (cp *Processor) processCreateContainerRequest(req containerEvent.CreateCont cnrBytes := cnr.Marshal() id := cid.NewFromMarshalledContainer(cnrBytes) - err = cp.checkPutContainer(cnr, cnrBytes, req.SessionToken, req.InvocationScript, req.VerificationScript, "", "") + err = cp.checkPutContainer(cnr, cnrBytes, req.SessionToken, req.InvocationScript, req.VerificationScript) if err != nil { cp.log.Error("container creation request failed check", zap.Stringer("container", id), zap.Error(err)) @@ -72,34 +72,6 @@ func (cp *Processor) processCreateContainerRequest(req containerEvent.CreateCont cp.approvePutContainer(req.MainTransaction, cnr, id) } -// Process a new container from the user by checking the container sanity -// and sending approve tx back to the FS chain. -func (cp *Processor) processContainerPut(req containerEvent.CreateContainerRequest, id cid.ID) { - if !cp.alphabetState.IsAlphabet() { - cp.log.Info("non alphabet mode, ignore container put") - return - } - - var cnr container.Container - if err := cnr.Unmarshal(req.Container); err != nil { - cp.log.Error("put container check failed", - zap.Error(fmt.Errorf("invalid binary container: %w", err)), - ) - return - } - - err := cp.checkPutContainer(cnr, req.Container, req.SessionToken, req.InvocationScript, req.VerificationScript, req.DomainName, req.DomainZone) - if err != nil { - cp.log.Error("put container check failed", - zap.Error(err), - ) - - return - } - - cp.approvePutContainer(req.MainTransaction, cnr, id) -} - const ( sysAttrPrefix = "__NEOFS__" sysAttrChainMeta = sysAttrPrefix + "METAINFO_CONSISTENCY" @@ -112,7 +84,7 @@ var allowedSystemAttributes = map[string]struct{}{ sysAttrChainMeta: {}, } -func (cp *Processor) checkPutContainer(cnr container.Container, cnrBytes, sessionToken, invocScript, verifScript []byte, domainName, domainZone string) error { +func (cp *Processor) checkPutContainer(cnr container.Container, cnrBytes, sessionToken, invocScript, verifScript []byte) error { if ver := cnr.Version(); ver.Compare(minContainerAPIVersion) < 0 { return fmt.Errorf("API version is %s while %s is minimum supported", ver, minContainerAPIVersion) } @@ -161,13 +133,6 @@ func (cp *Processor) checkPutContainer(cnr container.Container, cnrBytes, sessio return fmt.Errorf("invalid storage policy: %w", err) } - if domainZone != "" { // if PutNamed event => check if values in-container domain name and zone correspond to args - err = checkNNS(cnr, domainName, domainZone) - if err != nil { - return fmt.Errorf("NNS: %w", err) - } - } - return nil } @@ -452,18 +417,3 @@ func (cp *Processor) approveRemoveAttributeRequest(req containerEvent.RemoveAttr zap.Stringer("container", id), zap.Error(err)) } } - -func checkNNS(cnr container.Container, name, zone string) error { - // fetch domain info - d := cnr.ReadDomain() - - if name != d.Name() { - return fmt.Errorf("names differ %s/%s", name, d.Name()) - } - - if zone != d.Zone() { - return fmt.Errorf("zones differ %s/%s", zone, d.Zone()) - } - - return nil -} diff --git a/pkg/innerring/processors/container/processor.go b/pkg/innerring/processors/container/processor.go index ebb6e01253..5743f77414 100644 --- a/pkg/innerring/processors/container/processor.go +++ b/pkg/innerring/processors/container/processor.go @@ -130,10 +130,6 @@ func (cp *Processor) ListenerNotaryParsers() []event.NotaryParserInfo { p.SetScriptHash(cp.cnrClient.ContractAddress()) // create container - p.SetRequestType(fschaincontracts.CreateContainerMethod) - p.SetUnaryParser(containerEvent.RestoreCreateContainerRequest) - pp = append(pp, p) - p.SetRequestType(fschaincontracts.CreateContainerV2Method) p.SetParser(containerEvent.RestoreCreateContainerV2Request) pp = append(pp, p) @@ -177,10 +173,6 @@ func (cp *Processor) ListenerNotaryHandlers() []event.NotaryHandlerInfo { h.SetScriptHash(cp.cnrClient.ContractAddress()) // create container - h.SetRequestType(fschaincontracts.CreateContainerMethod) - h.SetHandler(cp.handlePut) - hh = append(hh, h) - h.SetRequestType(fschaincontracts.CreateContainerV2Method) h.SetHandler(cp.handleCreationRequest) hh = append(hh, h) diff --git a/pkg/morph/client/container/client.go b/pkg/morph/client/container/client.go index 5675b8b646..50967d52ad 100644 --- a/pkg/morph/client/container/client.go +++ b/pkg/morph/client/container/client.go @@ -3,9 +3,7 @@ package container import ( "errors" "fmt" - "strings" - "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neofs-node/pkg/morph/client" ) @@ -23,11 +21,7 @@ type Client struct { } const ( - putMethod = "put" - getDataMethod = "getContainerData" - getInfoMethod = "getInfo" getInfoRevisionedMethod = "getRevisionedInfo" - listMethod = "containersOf" eaclDataMethod = "getEACLData" tokensOfMethod = "tokensOf" tokensMethod = "tokens" @@ -97,14 +91,3 @@ func AsAlphabet() Option { o.staticOpts = append(o.staticOpts, client.AsAlphabet()) } } - -func isMethodNotFoundError(err error, mtd string) bool { - if exc, ok := errors.AsType[unwrap.Exception](err); ok { - return isMethodNotFoundException(string(exc), mtd) - } - return isMethodNotFoundException(err.Error(), mtd) -} - -func isMethodNotFoundException(msg, mtd string) bool { - return strings.Contains(msg, "method not found: "+mtd) -} diff --git a/pkg/morph/client/container/get.go b/pkg/morph/client/container/get.go index 8411ed2aec..f5a9ac2dba 100644 --- a/pkg/morph/client/container/get.go +++ b/pkg/morph/client/container/get.go @@ -4,7 +4,6 @@ import ( "fmt" "strings" - "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" containerrpc "github.com/nspcc-dev/neofs-contract/rpc/container" containercore "github.com/nspcc-dev/neofs-node/pkg/core/container" "github.com/nspcc-dev/neofs-node/pkg/morph/client" @@ -38,58 +37,24 @@ func Get(c *Client, cnr cid.ID) (container.Container, error) { func (c *Client) Get(cid []byte) (container.Container, error) { var cnr container.Container prm := client.TestInvokePrm{} - method := getInfoRevisionedMethod - prm.SetMethod(method) + prm.SetMethod(getInfoRevisionedMethod) prm.SetArgs(cid) arr, err := c.client.TestInvoke(prm) - if err != nil && isMethodNotFoundError(err, method) { - method = getInfoMethod - prm.SetMethod(method) - arr, err = c.client.TestInvoke(prm) - if err != nil && isMethodNotFoundError(err, method) { - method = getDataMethod - prm.SetMethod(method) - arr, err = c.client.TestInvoke(prm) - } - } if err != nil { if strings.Contains(err.Error(), containerrpc.NotFoundError) { var errNotFound apistatus.ContainerNotFound return cnr, errNotFound } - return cnr, fmt.Errorf("could not perform test invocation (%s): %w", method, err) + return cnr, fmt.Errorf("could not perform test invocation (%s): %w", getInfoRevisionedMethod, err) } else if ln := len(arr); ln != 1 { - return cnr, fmt.Errorf("unexpected stack item count (%s): %d", method, ln) + return cnr, fmt.Errorf("unexpected stack item count (%s): %d", getInfoRevisionedMethod, ln) } - switch method { - case getInfoRevisionedMethod: - cnr, err = revisionedContainerFromStackItem(arr[0]) - case getInfoMethod: - cnr, err = containerFromStackItem(arr[0]) - default: - cnr, err = decodeOldGetResponse(arr, method) - } + cnr, err = revisionedContainerFromStackItem(arr[0]) if err != nil { - return cnr, fmt.Errorf("invalid %q method result: invalid stack item: %w", method, err) - } - - return cnr, nil -} - -func decodeOldGetResponse(arr []stackitem.Item, method string) (container.Container, error) { - var cnr container.Container - - cnrBytes, err := client.BytesFromStackItem(arr[0]) - if err != nil { - return cnr, fmt.Errorf("could not get byte array of container (%s): %w", method, err) - } - - if err := cnr.Unmarshal(cnrBytes); err != nil { - // use other major version if there any - return cnr, fmt.Errorf("can't unmarshal container: %w", err) + return cnr, fmt.Errorf("invalid %q method result: invalid stack item: %w", getInfoRevisionedMethod, err) } return cnr, nil diff --git a/pkg/morph/client/container/list.go b/pkg/morph/client/container/list.go index 88df90ee2a..d7e0a77531 100644 --- a/pkg/morph/client/container/list.go +++ b/pkg/morph/client/container/list.go @@ -25,15 +25,6 @@ func (c *Client) List(idUser *user.ID) ([]cid.ID, error) { } res, err := c.client.TestInvokeIterator(mtd, iteratorPrefetchNumber, args...) - if err != nil && isMethodNotFoundError(err, mtd) { - var rawIdUser []byte - if idUser != nil { - rawIdUser = idUser[:] - } - - res, err = c.client.TestInvokeIterator(listMethod, iteratorPrefetchNumber, rawIdUser) - mtd = listMethod - } if err != nil { return nil, fmt.Errorf("could not perform test invocation (%s): %w", mtd, err) } diff --git a/pkg/morph/client/container/models.go b/pkg/morph/client/container/models.go index 5f9e2c6459..30a4bfd646 100644 --- a/pkg/morph/client/container/models.go +++ b/pkg/morph/client/container/models.go @@ -45,15 +45,6 @@ func revisionedContainerFromStackItem(item stackitem.Item) (container.Container, return cnr, nil } -func containerFromStackItem(item stackitem.Item) (container.Container, error) { - var contractStruct containerrpc.ContainerInfo - if err := contractStruct.FromStackItem(item); err != nil { - return container.Container{}, err - } - - return ContainerFromStruct(contractStruct) -} - // ContainerFromStruct decodes container from contract structure. func ContainerFromStruct(contractStruct containerrpc.ContainerInfo) (container.Container, error) { mjr, mnr, err := containerVersionFromStruct(contractStruct.Version) diff --git a/pkg/morph/client/container/put.go b/pkg/morph/client/container/put.go index da796dd69d..85e4306191 100644 --- a/pkg/morph/client/container/put.go +++ b/pkg/morph/client/container/put.go @@ -70,34 +70,11 @@ func (c *Client) Put(ctx context.Context, p PutPrm) (cid.ID, error) { err := c.client.CallWithAlphabetWitness(ctx, fschaincontracts.CreateContainerV2Method, []any{ containerToStackItem(p.cnr), p.sig, p.key, p.token, }) - if err == nil { - return cid.NewFromMarshalledContainer(p.cnr.Marshal()), nil - } - if !isMethodNotFoundError(err, fschaincontracts.CreateContainerV2Method) { + if err != nil { return cid.ID{}, fmt.Errorf("could not invoke method (%s): %w", fschaincontracts.CreateContainerV2Method, err) } - domain := p.cnr.ReadDomain() - metaAttr := p.cnr.Attribute("__NEOFS__METAINFO_CONSISTENCY") - metaEnabled := metaAttr == "optimistic" || metaAttr == "strict" - cnrBytes := p.cnr.Marshal() - - err = c.client.CallWithAlphabetWitness(ctx, fschaincontracts.CreateContainerMethod, []any{ - cnrBytes, p.sig, p.key, p.token, domain.Name(), domain.Zone(), metaEnabled, - }) - if err != nil { - if isMethodNotFoundError(err, fschaincontracts.CreateContainerMethod) { - err = c.client.CallWithAlphabetWitness(ctx, putMethod, []any{ - cnrBytes, p.sig, p.key, p.token, domain.Name(), domain.Zone(), metaEnabled, - }) - if err != nil { - return cid.ID{}, fmt.Errorf("could not invoke method (%s): %w", putMethod, err) - } - return cid.NewFromMarshalledContainer(cnrBytes), nil - } - return cid.ID{}, fmt.Errorf("could not invoke method (%s): %w", fschaincontracts.CreateContainerMethod, err) - } - return cid.NewFromMarshalledContainer(cnrBytes), nil + return cid.NewFromMarshalledContainer(p.cnr.Marshal()), nil } func (c *Client) putContainerWithEacl(ctx context.Context, p PutPrm) (cid.ID, error) { diff --git a/pkg/morph/contracts/methods.go b/pkg/morph/contracts/methods.go index 83a2d2c9ae..0dbe4a8400 100644 --- a/pkg/morph/contracts/methods.go +++ b/pkg/morph/contracts/methods.go @@ -4,7 +4,6 @@ package fschaincontracts const ( PayBalanceMethod = "settleContainerPayment" UnpaidBalanceMethod = "getUnpaidContainerEpoch" - CreateContainerMethod = "create" CreateContainerV2Method = "createV2" RemoveContainerMethod = "remove" PutContainerEACLMethod = "putEACL" diff --git a/pkg/morph/event/container/notary_requests.go b/pkg/morph/event/container/notary_requests.go index 514a8fa328..068ed6b1e6 100644 --- a/pkg/morph/event/container/notary_requests.go +++ b/pkg/morph/event/container/notary_requests.go @@ -166,51 +166,6 @@ func containerAttributeFromPushedItem(instr scparser.PushedItem) (*containerrpc. return res, nil } -// CreateContainerRequest wraps container creation request to provide -// app-internal event. -type CreateContainerRequest struct { - event.Event - MainTransaction transaction.Transaction - fschaincontracts.CreateContainerParams -} - -// RestoreCreateContainerRequest restores [CreateContainerRequest] from the -// notary one. -func RestoreCreateContainerRequest(notaryReq event.NotaryEvent) (event.Event, error) { - const argNum = 7 - args, err := event.GetArgs(notaryReq, argNum) - if err != nil { - return nil, err - } - - var res CreateContainerRequest - - if res.Container, err = event.GetValueFromArg(args, 0, notaryReq.Type().String(), scparser.GetBytesFromInstr); err != nil { - return nil, err - } - if res.InvocationScript, err = event.GetValueFromArg(args, 1, notaryReq.Type().String(), scparser.GetBytesFromInstr); err != nil { - return nil, err - } - if res.VerificationScript, err = event.GetValueFromArg(args, 2, notaryReq.Type().String(), scparser.GetBytesFromInstr); err != nil { - return nil, err - } - if res.SessionToken, err = event.GetValueFromArg(args, 3, notaryReq.Type().String(), scparser.GetBytesFromInstr); err != nil { - return nil, err - } - if res.DomainName, err = event.GetValueFromArg(args, 4, notaryReq.Type().String(), scparser.GetStringFromInstr); err != nil { - return nil, err - } - if res.DomainZone, err = event.GetValueFromArg(args, 5, notaryReq.Type().String(), scparser.GetStringFromInstr); err != nil { - return nil, err - } - if res.EnableObjectMetadata, err = event.GetValueFromArg(args, 6, notaryReq.Type().String(), scparser.GetBoolFromInstr); err != nil { - return nil, err - } - res.MainTransaction = *notaryReq.Raw().MainTransaction - - return res, nil -} - // RemoveContainerRequest wraps container removal request to provide // app-internal event. type RemoveContainerRequest struct { diff --git a/pkg/morph/event/container/notifications.go b/pkg/morph/event/container/notifications.go index c6acf3cccc..f76fd597e2 100644 --- a/pkg/morph/event/container/notifications.go +++ b/pkg/morph/event/container/notifications.go @@ -10,8 +10,6 @@ import ( "github.com/nspcc-dev/neofs-node/pkg/morph/client" "github.com/nspcc-dev/neofs-node/pkg/morph/event" cid "github.com/nspcc-dev/neofs-sdk-go/container/id" - "github.com/nspcc-dev/neofs-sdk-go/proto/refs" - "github.com/nspcc-dev/neofs-sdk-go/user" ) func getItemsFromNotification(notifEvent *state.ContainedNotificationEvent, expectedNum int) ([]stackitem.Item, error) { @@ -30,78 +28,6 @@ func restoreItemValue[T any](items []stackitem.Item, i int, desc string, typ sta return v, nil } -// Created is a container creation event thrown by Container contract. -type Created struct { - event.Event - ID cid.ID - Owner user.ID -} - -// RestoreCreated restores [Created] event from the notification one. -func RestoreCreated(notifEvent *state.ContainedNotificationEvent) (event.Event, error) { - items, err := getItemsFromNotification(notifEvent, 2) - if err != nil { - return nil, err - } - - id, err := restoreItemValue(items, 0, "ID", stackitem.ByteArrayT, client.BytesFromStackItem) - if err != nil { - return nil, err - } - owner, err := restoreItemValue(items, 1, "owner", stackitem.ByteArrayT, client.BytesFromStackItem) - if err != nil { - return nil, err - } - - var res Created - - if err = res.ID.Decode(id); err != nil { - return nil, fmt.Errorf("decode ID item: %w", err) - } - // TODO: replace message decoding after https://github.com/nspcc-dev/neofs-sdk-go/issues/669 - if err = res.Owner.FromProtoMessage(&refs.OwnerID{Value: owner}); err != nil { - return nil, fmt.Errorf("decode owner item: %w", err) - } - - return res, nil -} - -// Removed is a container removal event thrown by Container contract. -type Removed struct { - event.Event - ID cid.ID - Owner user.ID -} - -// RestoreRemoved restores [Removed] event from the notification one. -func RestoreRemoved(notifEvent *state.ContainedNotificationEvent) (event.Event, error) { - items, err := getItemsFromNotification(notifEvent, 2) - if err != nil { - return nil, err - } - - id, err := restoreItemValue(items, 0, "ID", stackitem.ByteArrayT, client.BytesFromStackItem) - if err != nil { - return nil, err - } - owner, err := restoreItemValue(items, 1, "owner", stackitem.ByteArrayT, client.BytesFromStackItem) - if err != nil { - return nil, err - } - - var res Removed - - if err = res.ID.Decode(id); err != nil { - return nil, fmt.Errorf("decode ID item: %w", err) - } - // TODO: replace message decoding after https://github.com/nspcc-dev/neofs-sdk-go/issues/669 - if err = res.Owner.FromProtoMessage(&refs.OwnerID{Value: owner}); err != nil { - return nil, fmt.Errorf("decode owner item: %w", err) - } - - return res, nil -} - // EACLChanged is a container eACL change event thrown by Container contract. type EACLChanged struct { event.Event