From f1f2101dc6a38a8c2cc29be4af6e167c9a780885 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 24 May 2022 12:55:36 +0300 Subject: [PATCH] [#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 --- container/config.yml | 2 +- container/container_contract.go | 15 +++++++++++++++ tests/container_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/container/config.yml b/container/config.yml index 82e0505..c75978e 100644 --- a/container/config.yml +++ b/container/config.yml @@ -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"] diff --git a/container/container_contract.go b/container/container_contract.go index a6e6849..c372123 100644 --- a/container/container_contract.go +++ b/container/container_contract.go @@ -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() diff --git a/tests/container_test.go b/tests/container_test.go index 32a8a4f..3b73a34 100644 --- a/tests/container_test.go +++ b/tests/container_test.go @@ -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)