Skip to content

Commit

Permalink
Feat/support meta with big objects (#457)
Browse files Browse the repository at this point in the history
  • Loading branch information
roman-khimov authored Dec 25, 2024
2 parents 4da43df + dd0efc8 commit 1a1dbb8
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 26 deletions.
75 changes: 57 additions & 18 deletions contracts/container/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,37 +248,67 @@ func Update(script []byte, manifest []byte, data any) {
// 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)

// required

cID := requireMapValue(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)
oID := requireMapValue(metaMap, "oid").(interop.Hash256)
if len(oID) != interop.Hash256Len {
panic("incorrect object ID")
}
magic := getFromMap(metaMap, "network").(int)
_ = requireMapValue(metaMap, "size").(int)
vub := requireMapValue(metaMap, "validUntil").(int)
if vub <= ledger.CurrentIndex() {
panic("incorrect vub: exceeded")
}
magic := requireMapValue(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")

// optional

if v, ok := getFromMap(metaMap, "type"); ok {
typ := v.(int)
switch typ {
case 0, 1, 2, 3, 4: // regular, tombstone, storage group, lock, link
default:
panic("incorrect object type")
}
}
locked := getFromMap(metaMap, "locked").([]interop.Hash256)
for i, l := range locked {
if len(l) != interop.Hash256Len {
panic("incorrect " + std.Itoa10(i) + " locked object")
if v, ok := getFromMap(metaMap, "firstPart"); ok {
firstPart := v.(interop.Hash256)
if len(firstPart) != interop.Hash256Len {
panic("incorrect first part object ID")
}
}
vub := getFromMap(metaMap, "validuntil").(int)
if vub <= ledger.CurrentIndex() {
panic("incorrect vub: exceeded")
if v, ok := getFromMap(metaMap, "previousPart"); ok {
previousPart := v.(interop.Hash256)
if len(previousPart) != interop.Hash256Len {
panic("incorrect previous part object ID")
}
}
if v, ok := getFromMap(metaMap, "locked"); ok {
locked := v.([]interop.Hash256)
for i, l := range locked {
if len(l) != interop.Hash256Len {
panic("incorrect " + std.Itoa10(i) + " locked object")
}
}
}
if v, ok := getFromMap(metaMap, "deleted"); ok {
deleted := v.([]interop.Hash256)
for i, d := range deleted {
if len(d) != interop.Hash256Len {
panic("incorrect " + std.Itoa10(i) + " deleted object")
}
}
}

if !VerifyPlacementSignatures(cID, metaInformation, sigs) {
Expand All @@ -288,12 +318,21 @@ func SubmitObjectPut(metaInformation []byte, sigs [][]interop.Signature) {
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
func requireMapValue(m map[string]any, key string) any {
v, ok := getFromMap(m, key)
if !ok {
panic("'" + key + "'" + " not found")
}

return m[key]
return v
}

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

return nil, false
}

// PutMeta is the same as [Put] and [PutNamed] (and exposed as put from
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":4717,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"},{"name":"publicKeys","type":"Array"}],"returntype":"Void","safe":false},{"name":"alias","offset":4427,"parameters":[{"name":"cid","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"commitContainerListUpdate","offset":5483,"parameters":[{"name":"cID","type":"Hash256"},{"name":"replicas","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"containersOf","offset":4567,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"count","offset":4522,"parameters":[],"returntype":"Integer","safe":true},{"name":"delete","offset":3924,"parameters":[{"name":"containerID","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"eACL","offset":6419,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"get","offset":4314,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getContainerSize","offset":6679,"parameters":[{"name":"id","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"iterateAllContainerSizes","offset":7052,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"iterateContainerSizes","offset":6954,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"list","offset":4621,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"listContainerSizes","offset":6793,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Array","safe":true},{"name":"newEpoch","offset":7104,"parameters":[{"name":"epochNum","type":"Integer"}],"returntype":"Void","safe":false},{"name":"nodes","offset":6042,"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":4376,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"put","offset":2753,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"putContainerSize","offset":6477,"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":"name","type":"String"},{"name":"zone","type":"String"},{"name":"metaOnChain","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"putNamed","offset":2783,"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":"put","offset":2769,"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":5944,"parameters":[{"name":"cID","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"setEACL","offset":6166,"parameters":[{"name":"eACL","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"startContainerEstimation","offset":7127,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"stopContainerEstimation","offset":7201,"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":5315,"parameters":[{"name":"cid","type":"Hash256"},{"name":"msg","type":"ByteArray"},{"name":"sigs","type":"Array"}],"returntype":"Boolean","safe":true},{"name":"version","offset":7274,"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}
{"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":5018,"parameters":[{"name":"cID","type":"Hash256"},{"name":"placementVector","type":"Integer"},{"name":"publicKeys","type":"Array"}],"returntype":"Void","safe":false},{"name":"alias","offset":4728,"parameters":[{"name":"cid","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"commitContainerListUpdate","offset":5784,"parameters":[{"name":"cID","type":"Hash256"},{"name":"replicas","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"containersOf","offset":4868,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"count","offset":4823,"parameters":[],"returntype":"Integer","safe":true},{"name":"delete","offset":4225,"parameters":[{"name":"containerID","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"eACL","offset":6720,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"get","offset":4615,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getContainerSize","offset":6980,"parameters":[{"name":"id","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"iterateAllContainerSizes","offset":7353,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"InteropInterface","safe":true},{"name":"iterateContainerSizes","offset":7255,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"list","offset":4922,"parameters":[{"name":"owner","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"listContainerSizes","offset":7094,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Array","safe":true},{"name":"newEpoch","offset":7405,"parameters":[{"name":"epochNum","type":"Integer"}],"returntype":"Void","safe":false},{"name":"nodes","offset":6343,"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":4677,"parameters":[{"name":"containerID","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"put","offset":3054,"parameters":[{"name":"container","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"putContainerSize","offset":6778,"parameters":[{"name":"epoch","type":"Integer"},{"name":"cid","type":"ByteArray"},{"name":"usedSize","type":"Integer"},{"name":"pubKey","type":"PublicKey"}],"returntype":"Void","safe":false},{"name":"put","offset":2991,"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"},{"name":"metaOnChain","type":"Boolean"}],"returntype":"Void","safe":false},{"name":"putNamed","offset":3084,"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":"put","offset":3070,"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":6245,"parameters":[{"name":"cID","type":"Hash256"}],"returntype":"InteropInterface","safe":true},{"name":"setEACL","offset":6467,"parameters":[{"name":"eACL","type":"ByteArray"},{"name":"signature","type":"Signature"},{"name":"publicKey","type":"PublicKey"},{"name":"token","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"startContainerEstimation","offset":7428,"parameters":[{"name":"epoch","type":"Integer"}],"returntype":"Void","safe":false},{"name":"stopContainerEstimation","offset":7502,"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":5616,"parameters":[{"name":"cid","type":"Hash256"},{"name":"msg","type":"ByteArray"},{"name":"sigs","type":"Array"}],"returntype":"Boolean","safe":true},{"name":"version","offset":7575,"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}
16 changes: 9 additions & 7 deletions tests/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ func TestPutMeta(t *testing.T) {
c.InvokeFail(t, "invalid type", "submitObjectPut", []byte{1}, nil)
})

t.Run("missing values", func(t *testing.T) {
t.Run("missing required values", func(t *testing.T) {
testFunc := func(key string) {
meta := testMeta(cnt.id[:], oid)
meta.Drop(meta.Index(stackitem.Make(key)))
Expand All @@ -872,11 +872,9 @@ func TestPutMeta(t *testing.T) {

testFunc("cid")
testFunc("oid")
testFunc("network")
testFunc("size")
testFunc("deleted")
testFunc("locked")
testFunc("validuntil")
testFunc("validUntil")
testFunc("network")
})

t.Run("incorrect values", func(t *testing.T) {
Expand All @@ -890,10 +888,13 @@ func TestPutMeta(t *testing.T) {

testFunc("cid", []byte{1})
testFunc("oid", []byte{1})
testFunc("validUntil", 1) // tested chain will have some blocks for sure
testFunc("network", netmode.UnitTestNet+1)
testFunc("type", math.MaxInt64)
testFunc("firstPart", []byte{1})
testFunc("previousPart", []byte{1})
testFunc("deleted", []any{[]byte{1}})
testFunc("locked", []any{[]byte{1}})
testFunc("validuntil", 1) // tested chain will have some blocks for sure
})
})
}
Expand All @@ -904,9 +905,10 @@ func testMeta(cid, oid []byte) *stackitem.Map {
{Key: stackitem.Make("network"), Value: stackitem.Make(netmode.UnitTestNet)},
{Key: stackitem.Make("cid"), Value: stackitem.Make(cid)},
{Key: stackitem.Make("oid"), Value: stackitem.Make(oid)},
{Key: stackitem.Make("firstPart"), Value: stackitem.Make(oid)},
{Key: stackitem.Make("size"), Value: stackitem.Make(123)},
{Key: stackitem.Make("deleted"), Value: stackitem.Make([]any{randomBytes(sha256.Size)})},
{Key: stackitem.Make("locked"), Value: stackitem.Make([]any{randomBytes(sha256.Size)})},
{Key: stackitem.Make("validuntil"), Value: stackitem.Make(math.MaxInt)},
{Key: stackitem.Make("validUntil"), Value: stackitem.Make(math.MaxInt)},
})
}

0 comments on commit 1a1dbb8

Please sign in to comment.