Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

container: add object meta notification support #448

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions contracts/container/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ events:
parameters:
- name: ContainerID
type: hash256
- name: ObjectPut
parameters:
- name: ContainerID
type: hash256
- name: ObjectID
type: hash256
- name: Meta
type: Map
overloads:
putMeta: put
89 changes: 80 additions & 9 deletions contracts/container/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/convert"
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neofs-contract/common"
Expand Down Expand Up @@ -61,15 +63,16 @@ const (
// V2 format.
containerIDSize = interop.Hash256Len // SHA256 size

singleEstimatePrefix = "est"
estimateKeyPrefix = "cnr"
containerKeyPrefix = 'x'
ownerKeyPrefix = 'o'
deletedKeyPrefix = 'd'
nodesPrefix = 'n'
replicasNumberPrefix = 'r'
nextEpochNodesPrefix = 'u'
estimatePostfixSize = 10
singleEstimatePrefix = "est"
estimateKeyPrefix = "cnr"
containersWithMetaPrefix = 'm'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a remark

i very like (no) how gofmt makes a 10-line change when one is actually added/changed. Takin bout why linebreaks are good sometimes, and const/var blocks aint

containerKeyPrefix = 'x'
ownerKeyPrefix = 'o'
deletedKeyPrefix = 'd'
nodesPrefix = 'n'
replicasNumberPrefix = 'r'
nextEpochNodesPrefix = 'u'
estimatePostfixSize = 10

// default SOA record field values.
defaultRefresh = 3600 // 1 hour
Expand Down Expand Up @@ -238,6 +241,73 @@ func Update(script []byte, manifest []byte, data any) {
runtime.Log("container contract updated")
}

// SubmitObjectPut registers successful object PUT operation and notifies about
// it. metaInformation must be signed by container nodes according to
// container's placement, see [VerifyPlacementSignatures]. metaInformation
// must contain information about an object placed to a container that was
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must contain information in what form? Lets describe, []byte is hard to guess

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what form

i think this will somehow appear somewhere. at least it should appear before node's 0.44.0 release and contract's 0.21. however, currently node also uses it as is and the format is not fixed or described

// created using [Put] ([PutMeta]) with enabled meta-on-chain option.
func SubmitObjectPut(metaInformation []byte, sigs [][]interop.Signature) {
metaMap := std.Deserialize(metaInformation).(map[string]any)
cID := getFromMap(metaMap, "cid").(interop.Hash256)
if len(cID) != interop.Hash256Len {
panic("incorrect container ID")
}
if storage.Get(storage.GetContext(), append([]byte{containersWithMetaPrefix}, cID...)) == nil {
panic("container does not support meta-on-chain")
}
oID := getFromMap(metaMap, "oid").(interop.Hash256)
if len(oID) != interop.Hash256Len {
panic("incorrect object ID")
}
magic := getFromMap(metaMap, "network").(int)
if magic != runtime.GetNetwork() {
panic("incorrect network magic")
}
_ = getFromMap(metaMap, "size").(int)
deleted := getFromMap(metaMap, "deleted").([]interop.Hash256)
for i, d := range deleted {
if len(d) != interop.Hash256Len {
panic("incorrect " + std.Itoa10(i) + " deleted object")
}
}
locked := getFromMap(metaMap, "locked").([]interop.Hash256)
for i, l := range locked {
if len(l) != interop.Hash256Len {
panic("incorrect " + std.Itoa10(i) + " locked object")
}
}
vub := getFromMap(metaMap, "validuntil").(int)
if vub <= ledger.CurrentIndex() {
panic("incorrect vub: exceeded")
}

if !VerifyPlacementSignatures(cID, metaInformation, sigs) {
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
panic("signature verification failed")
}

runtime.Notify("ObjectPut", cID, oID, metaMap)
}

func getFromMap(m map[string]any, key string) any {
if !neogointernal.Opcode2("HASKEY", m, key).(bool) { // https://github.com/nspcc-dev/neo-go/issues/3716
panic("'" + key + "'" + " not found")
}

return m[key]
}

// PutMeta is the same as [Put] (and exposed as put from the contract via
// overload), but allows container's meta-information be handled and notified
// using the chain.
func PutMeta(container []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte, metaOnChain bool) {
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we put container and just configure meta support, with this PutMeta name can confuse. I can suggest PutWithTunedMeta, but not very against ur proposal

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have adopted @roman-khimov's approach with method overloading. no one will call it putMeta, it is the same put but with one more arg. i really liked it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put but with one more arg - putWithMeta to me

if metaOnChain {
ctx := storage.GetContext()
cID := crypto.Sha256(container)
storage.Put(ctx, append([]byte{containersWithMetaPrefix}, cID...), []byte{})
}
Put(container, signature, publicKey, token)
}

// Put method creates a new container if it has been invoked by Alphabet nodes
// of the Inner Ring. Otherwise, it produces containerPut notification.
//
Expand Down Expand Up @@ -950,6 +1020,7 @@ func removeContainer(ctx storage.Context, id []byte, owner []byte) {
storage.Delete(ctx, containerListKey)

storage.Delete(ctx, append([]byte{containerKeyPrefix}, id...))
storage.Delete(ctx, append([]byte{containersWithMetaPrefix}, id...))
storage.Delete(ctx, append(eACLPrefix, id...))
storage.Put(ctx, append([]byte{deletedKeyPrefix}, id...), []byte{})
}
Expand Down
Binary file modified contracts/container/contract.nef
Binary file not shown.
2 changes: 1 addition & 1 deletion contracts/container/manifest.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"name":"NeoFS Container","abi":{"methods":[{"name":"_initialize","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"_deploy","offset":83,"parameters":[{"name":"data","type":"Any"},{"name":"isUpdate","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"addNextEpochNodes","offset":3988,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"},{"name":"publicKeys","type":"Array"}],"returntype":"Void","safe":false},{"name":"alias","offset":3698,"parameters":[{"name":"cid","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"commitContainerListUpdate","offset":4752,"parameters":[{"name":"cID","type":"Hash256"},{"name":"replicas","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"containersOf","offset":3838,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"count","offset":3793,"parameters":[],"returntype":"Integer","safe":true},{"name":"delete","offset":3195,"parameters":[{"name":"containerID","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"eACL","offset":5688,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"get","offset":3585,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getContainerSize","offset":5948,"parameters":[{"name":"id","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"iterateAllContainerSizes","offset":6321,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"iterateContainerSizes","offset":6223,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"list","offset":3892,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"listContainerSizes","offset":6062,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Array","safe":true},{"name":"newEpoch","offset":6373,"parameters":[{"name":"epochNum","type":"Integer"}],"returntype":"Void","safe":false},{"name":"nodes","offset":5311,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"onNEP11Payment","offset":1647,"parameters":[{"name":"a","type":"Hash160"},{"name":"b","type":"Integer"},{"name":"c","type":"ByteArray"},{"name":"d","type":"Any"}],"returntype":"Void","safe":false},{"name":"owner","offset":3647,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"put","offset":2038,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"putContainerSize","offset":5746,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"ByteArray"},{"name":"usedSize","type":"Integer"},{"name":"pubKey","type":"PublicKey"}],"returntype":"Void","safe":false},{"name":"putNamed","offset":2054,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"},{"name":"name","type":"String"},{"name":"zone","type":"String"}],"returntype":"Void","safe":false},{"name":"replicasNumbers","offset":5213,"parameters":[{"name":"cID","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"setEACL","offset":5435,"parameters":[{"name":"eACL","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"startContainerEstimation","offset":6396,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"stopContainerEstimation","offset":6470,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"update","offset":1905,"parameters":[{"name":"script","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"verifyPlacementSignatures","offset":4586,"parameters":[{"name":"cid","type":"Hash256"},{"name":"msg","type":"ByteArray"},{"name":"sigs","type":"Array"}],"returntype":"Boolean","safe":true},{"name":"version","offset":6543,"parameters":[],"returntype":"Integer","safe":true}],"events":[{"name":"PutSuccess","parameters":[{"name":"containerID","type":"Hash256"},{"name":"publicKey","type":"PublicKey"}]},{"name":"DeleteSuccess","parameters":[{"name":"containerID","type":"ByteArray"}]},{"name":"SetEACLSuccess","parameters":[{"name":"containerID","type":"ByteArray"},{"name":"publicKey","type":"PublicKey"}]},{"name":"StartEstimation","parameters":[{"name":"epoch","type":"Integer"}]},{"name":"StopEstimation","parameters":[{"name":"epoch","type":"Integer"}]},{"name":"NodesUpdate","parameters":[{"name":"ContainerID","type":"Hash256"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":["update","addKey","transferX","register","registerTLD","addRecord","deleteRecords","subscribeForNewEpoch"]}],"supportedstandards":[],"trusts":[],"extra":null}
{"name":"NeoFS Container","abi":{"methods":[{"name":"_initialize","offset":0,"parameters":[],"returntype":"Void","safe":false},{"name":"_deploy","offset":83,"parameters":[{"name":"data","type":"Any"},{"name":"isUpdate","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"addNextEpochNodes","offset":4700,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"},{"name":"publicKeys","type":"Array"}],"returntype":"Void","safe":false},{"name":"alias","offset":4410,"parameters":[{"name":"cid","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"commitContainerListUpdate","offset":5464,"parameters":[{"name":"cID","type":"Hash256"},{"name":"replicas","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"containersOf","offset":4550,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"count","offset":4505,"parameters":[],"returntype":"Integer","safe":true},{"name":"delete","offset":3907,"parameters":[{"name":"containerID","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"eACL","offset":6400,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"get","offset":4297,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getContainerSize","offset":6660,"parameters":[{"name":"id","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"iterateAllContainerSizes","offset":7033,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"iterateContainerSizes","offset":6935,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"list","offset":4604,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"listContainerSizes","offset":6774,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Array","safe":true},{"name":"newEpoch","offset":7085,"parameters":[{"name":"epochNum","type":"Integer"}],"returntype":"Void","safe":false},{"name":"nodes","offset":6023,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"onNEP11Payment","offset":1647,"parameters":[{"name":"a","type":"Hash160"},{"name":"b","type":"Integer"},{"name":"c","type":"ByteArray"},{"name":"d","type":"Any"}],"returntype":"Void","safe":false},{"name":"owner","offset":4359,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"put","offset":2750,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"putContainerSize","offset":6458,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"ByteArray"},{"name":"usedSize","type":"Integer"},{"name":"pubKey","type":"PublicKey"}],"returntype":"Void","safe":false},{"name":"put","offset":2690,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"},{"name":"metaOnChain","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"putNamed","offset":2766,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"},{"name":"name","type":"String"},{"name":"zone","type":"String"}],"returntype":"Void","safe":false},{"name":"replicasNumbers","offset":5925,"parameters":[{"name":"cID","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"setEACL","offset":6147,"parameters":[{"name":"eACL","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"startContainerEstimation","offset":7108,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"stopContainerEstimation","offset":7182,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"submitObjectPut","offset":2038,"parameters":[{"name":"metaInformation","type":"ByteArray"},{"name":"sigs","type":"Array"}],"returntype":"Void","safe":false},{"name":"update","offset":1905,"parameters":[{"name":"script","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false},{"name":"verifyPlacementSignatures","offset":5298,"parameters":[{"name":"cid","type":"Hash256"},{"name":"msg","type":"ByteArray"},{"name":"sigs","type":"Array"}],"returntype":"Boolean","safe":true},{"name":"version","offset":7255,"parameters":[],"returntype":"Integer","safe":true}],"events":[{"name":"PutSuccess","parameters":[{"name":"containerID","type":"Hash256"},{"name":"publicKey","type":"PublicKey"}]},{"name":"DeleteSuccess","parameters":[{"name":"containerID","type":"ByteArray"}]},{"name":"SetEACLSuccess","parameters":[{"name":"containerID","type":"ByteArray"},{"name":"publicKey","type":"PublicKey"}]},{"name":"StartEstimation","parameters":[{"name":"epoch","type":"Integer"}]},{"name":"StopEstimation","parameters":[{"name":"epoch","type":"Integer"}]},{"name":"NodesUpdate","parameters":[{"name":"ContainerID","type":"Hash256"}]},{"name":"ObjectPut","parameters":[{"name":"ContainerID","type":"Hash256"},{"name":"ObjectID","type":"Hash256"},{"name":"Meta","type":"Map"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":["update","addKey","transferX","register","registerTLD","addRecord","deleteRecords","subscribeForNewEpoch"]}],"supportedstandards":[],"trusts":[],"extra":null}
Loading
Loading