forked from TrueCloudLab/frostfs-contract
container: Add DeletionInfo() method
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
2b1fa53b67
commit
c6a7820363
3 changed files with 57 additions and 1 deletions
|
@ -2,6 +2,7 @@ name: "Container"
|
||||||
safemethods:
|
safemethods:
|
||||||
- "count"
|
- "count"
|
||||||
- "containersOf"
|
- "containersOf"
|
||||||
|
- "deletionInfo"
|
||||||
- "eACL"
|
- "eACL"
|
||||||
- "get"
|
- "get"
|
||||||
- "getContainerSize"
|
- "getContainerSize"
|
||||||
|
|
|
@ -64,6 +64,7 @@ const (
|
||||||
estimateKeyPrefix = "cnr"
|
estimateKeyPrefix = "cnr"
|
||||||
containerKeyPrefix = 'x'
|
containerKeyPrefix = 'x'
|
||||||
ownerKeyPrefix = 'o'
|
ownerKeyPrefix = 'o'
|
||||||
|
graveKeyPrefix = 'g'
|
||||||
estimatePostfixSize = 10
|
estimatePostfixSize = 10
|
||||||
// CleanupDelta contains the number of the last epochs for which container estimations are present.
|
// CleanupDelta contains the number of the last epochs for which container estimations are present.
|
||||||
CleanupDelta = 3
|
CleanupDelta = 3
|
||||||
|
@ -337,6 +338,25 @@ func Delete(containerID []byte, signature interop.Signature, publicKey interop.P
|
||||||
runtime.Notify("DeleteSuccess", containerID)
|
runtime.Notify("DeleteSuccess", containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DelInfo struct {
|
||||||
|
Owner interop.Hash160
|
||||||
|
Epoch int
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeletionInfo method returns container deletion info.
|
||||||
|
// If the container had never existed, NotFoundError is throwed.
|
||||||
|
// It can be used to check whether non-existing container was indeed deleted
|
||||||
|
// or does not yet exist at some height.
|
||||||
|
func DeletionInfo(containerID []byte) DelInfo {
|
||||||
|
ctx := storage.GetReadOnlyContext()
|
||||||
|
graveKey := append([]byte{graveKeyPrefix}, containerID...)
|
||||||
|
data := storage.Get(ctx, graveKey).([]byte)
|
||||||
|
if data == nil {
|
||||||
|
panic(NotFoundError)
|
||||||
|
}
|
||||||
|
return std.Deserialize(data).(DelInfo)
|
||||||
|
}
|
||||||
|
|
||||||
// Get method returns a structure that contains a stable marshaled Container structure,
|
// Get method returns a structure that contains a stable marshaled Container structure,
|
||||||
// the signature, the public key of the container creator and a stable marshaled SessionToken
|
// the signature, the public key of the container creator and a stable marshaled SessionToken
|
||||||
// structure if it was provided.
|
// structure if it was provided.
|
||||||
|
@ -596,6 +616,9 @@ func addContainer(ctx storage.Context, id, owner []byte, container Container) {
|
||||||
|
|
||||||
idKey := append([]byte{containerKeyPrefix}, id...)
|
idKey := append([]byte{containerKeyPrefix}, id...)
|
||||||
common.SetSerialized(ctx, idKey, container)
|
common.SetSerialized(ctx, idKey, container)
|
||||||
|
|
||||||
|
graveKey := append([]byte{graveKeyPrefix}, id...)
|
||||||
|
storage.Delete(ctx, graveKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeContainer(ctx storage.Context, id []byte, owner []byte) {
|
func removeContainer(ctx storage.Context, id []byte, owner []byte) {
|
||||||
|
@ -604,6 +627,14 @@ func removeContainer(ctx storage.Context, id []byte, owner []byte) {
|
||||||
storage.Delete(ctx, containerListKey)
|
storage.Delete(ctx, containerListKey)
|
||||||
|
|
||||||
storage.Delete(ctx, append([]byte{containerKeyPrefix}, id...))
|
storage.Delete(ctx, append([]byte{containerKeyPrefix}, id...))
|
||||||
|
|
||||||
|
graveKey := append([]byte{graveKeyPrefix}, id...)
|
||||||
|
netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160)
|
||||||
|
epoch := contract.Call(netmapContractAddr, "epoch", contract.ReadOnly).(int)
|
||||||
|
common.SetSerialized(ctx, graveKey, DelInfo{
|
||||||
|
Owner: owner,
|
||||||
|
Epoch: epoch,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllContainers(ctx storage.Context) [][]byte {
|
func getAllContainers(ctx storage.Context) [][]byte {
|
||||||
|
|
|
@ -243,19 +243,43 @@ func addContainer(t *testing.T, c, cBal *neotest.ContractInvoker) (neotest.Signe
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerDelete(t *testing.T) {
|
func TestContainerDelete(t *testing.T) {
|
||||||
c, cBal, _ := newContainerInvoker(t)
|
c, cBal, cNm := newContainerInvoker(t)
|
||||||
|
|
||||||
acc, cnt := addContainer(t, c, cBal)
|
acc, cnt := addContainer(t, c, cBal)
|
||||||
cAcc := c.WithSigners(acc)
|
cAcc := c.WithSigners(acc)
|
||||||
cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "delete",
|
cAcc.InvokeFail(t, common.ErrAlphabetWitnessFailed, "delete",
|
||||||
cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
||||||
|
|
||||||
|
newDelInfo := func(acc neotest.Signer, epoch int64) *stackitem.Struct {
|
||||||
|
return stackitem.NewStruct([]stackitem.Item{
|
||||||
|
stackitem.NewBuffer([]byte(signerToOwner(acc))),
|
||||||
|
stackitem.NewBigInteger(big.NewInt(epoch)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.InvokeFail(t, container.NotFoundError, "deletionInfo", cnt.id[:])
|
||||||
c.Invoke(t, stackitem.Null{}, "delete", cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
c.Invoke(t, stackitem.Null{}, "delete", cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
||||||
|
c.Invoke(t, newDelInfo(acc, 0), "deletionInfo", cnt.id[:])
|
||||||
|
|
||||||
|
t.Run("multi-epoch", func(t *testing.T) {
|
||||||
|
cNm.Invoke(t, stackitem.Null{}, "newEpoch", 1)
|
||||||
|
|
||||||
|
t.Run("epoch tick does not change deletion info", func(t *testing.T) {
|
||||||
|
c.Invoke(t, stackitem.Null{}, "delete", cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
||||||
|
c.Invoke(t, newDelInfo(acc, 0), "deletionInfo", cnt.id[:])
|
||||||
|
})
|
||||||
|
|
||||||
|
acc1, cnt1 := addContainer(t, c, cBal)
|
||||||
|
c.Invoke(t, stackitem.Null{}, "delete", cnt1.id[:], cnt1.sig, cnt1.pub, cnt1.token)
|
||||||
|
c.Invoke(t, newDelInfo(acc, 0), "deletionInfo", cnt.id[:])
|
||||||
|
c.Invoke(t, newDelInfo(acc1, 1), "deletionInfo", cnt1.id[:])
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("missing container", func(t *testing.T) {
|
t.Run("missing container", func(t *testing.T) {
|
||||||
id := cnt.id
|
id := cnt.id
|
||||||
id[0] ^= 0xFF
|
id[0] ^= 0xFF
|
||||||
c.Invoke(t, stackitem.Null{}, "delete", cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
c.Invoke(t, stackitem.Null{}, "delete", cnt.id[:], cnt.sig, cnt.pub, cnt.token)
|
||||||
|
c.InvokeFail(t, container.NotFoundError, "deletionInfo", id[:])
|
||||||
})
|
})
|
||||||
|
|
||||||
c.InvokeFail(t, container.NotFoundError, "get", cnt.id[:])
|
c.InvokeFail(t, container.NotFoundError, "get", cnt.id[:])
|
||||||
|
|
Loading…
Reference in a new issue