[#242] container: allow to fetch total amount of countainers

There are 2 approaches:
1. Use `storage.Find` to enumerate all containers.
2. Store a counter by a separate key.

Here we implemented 1, because this method is readonly (thus GAS cost it
not a problem) and simpler to implement.

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2022-05-24 12:55:36 +03:00 committed by fyrchik
parent 335b04d9a6
commit f1f2101dc6
3 changed files with 49 additions and 1 deletions

View file

@ -1,5 +1,5 @@
name: "NeoFS Container"
safemethods: ["get", "owner", "list", "eACL", "getContainerSize", "listContainerSizes", "version"]
safemethods: ["count", "get", "owner", "list", "eACL", "getContainerSize", "listContainerSizes", "version"]
permissions:
- methods: ["update", "addKey", "transferX",
"addRoot", "register", "addRecord", "deleteRecords"]

View file

@ -387,6 +387,21 @@ func Owner(containerID []byte) []byte {
return owner
}
// Count method returns the number of registered containers.
func Count() int {
count := 0
ctx := storage.GetReadOnlyContext()
it := storage.Find(ctx, []byte{}, storage.KeysOnly)
for iterator.Next(it) {
key := iterator.Value(it).([]byte)
// V2 format
if len(key) == containerIDSize {
count++
}
}
return count
}
// List method returns a list of all container IDs owned by the specified owner.
func List(owner []byte) [][]byte {
ctx := storage.GetReadOnlyContext()

View file

@ -79,6 +79,39 @@ func dummyContainer(owner neotest.Signer) testContainer {
}
}
func TestContainerCount(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)
checkCount := func(t *testing.T, expected int64) {
s, err := c.TestInvoke(t, "count")
require.NoError(t, err)
bi := s.Pop().BigInt()
require.True(t, bi.IsInt64())
require.Equal(t, int64(expected), bi.Int64())
}
checkCount(t, 0)
acc1, cnt1 := addContainer(t, c, cBal)
checkCount(t, 1)
_, cnt2 := addContainer(t, c, cBal)
checkCount(t, 2)
// Same owner.
cnt3 := dummyContainer(acc1)
balanceMint(t, cBal, acc1, containerFee*1, []byte{})
c.Invoke(t, stackitem.Null{}, "put", cnt3.value, cnt3.sig, cnt3.pub, cnt3.token)
c.Invoke(t, stackitem.Null{}, "delete", cnt1.id[:], cnt1.sig, cnt1.token)
checkCount(t, 2)
c.Invoke(t, stackitem.Null{}, "delete", cnt2.id[:], cnt2.sig, cnt2.token)
checkCount(t, 1)
c.Invoke(t, stackitem.Null{}, "delete", cnt3.id[:], cnt3.sig, cnt3.token)
checkCount(t, 0)
}
func TestContainerPut(t *testing.T) {
c, cBal, _ := newContainerInvoker(t)