forked from TrueCloudLab/frostfs-contract
[#142] container: panic on missing container
Return more descriptive error message for a user. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
654fc371fd
commit
6bd088aa9f
2 changed files with 101 additions and 12 deletions
|
@ -61,6 +61,9 @@ const (
|
||||||
estimateKeyPrefix = "cnr"
|
estimateKeyPrefix = "cnr"
|
||||||
estimatePostfixSize = 10
|
estimatePostfixSize = 10
|
||||||
cleanupDelta = 3
|
cleanupDelta = 3
|
||||||
|
|
||||||
|
// NotFoundError is returned if container is missing.
|
||||||
|
NotFoundError = "container does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -292,13 +295,15 @@ func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool
|
||||||
// Signature is a RFC6979 signature of container ID.
|
// Signature is a RFC6979 signature of container ID.
|
||||||
// Token is optional and should be stable marshaled SessionToken structure from
|
// Token is optional and should be stable marshaled SessionToken structure from
|
||||||
// API.
|
// API.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func Delete(containerID []byte, signature interop.Signature, token []byte) {
|
func Delete(containerID []byte, signature interop.Signature, token []byte) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
|
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
|
||||||
|
|
||||||
ownerID := getOwnerByID(ctx, containerID)
|
ownerID := getOwnerByID(ctx, containerID)
|
||||||
if len(ownerID) == 0 {
|
if ownerID == nil {
|
||||||
return
|
panic(NotFoundError)
|
||||||
}
|
}
|
||||||
|
|
||||||
if notaryDisabled {
|
if notaryDisabled {
|
||||||
|
@ -345,15 +350,27 @@ func Delete(containerID []byte, signature interop.Signature, token []byte) {
|
||||||
// Get method returns structure that contains stable marshaled Container structure,
|
// Get method returns structure that contains stable marshaled Container structure,
|
||||||
// signature, public key of the container creator and stable marshaled SessionToken
|
// signature, public key of the container creator and stable marshaled SessionToken
|
||||||
// structure if it was provided.
|
// structure if it was provided.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func Get(containerID []byte) Container {
|
func Get(containerID []byte) Container {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
return getContainer(ctx, containerID)
|
cnt := getContainer(ctx, containerID)
|
||||||
|
if len(cnt.value) == 0 {
|
||||||
|
panic(NotFoundError)
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Owner method returns 25 byte Owner ID of the container.
|
// Owner method returns 25 byte Owner ID of the container.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func Owner(containerID []byte) []byte {
|
func Owner(containerID []byte) []byte {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
return getOwnerByID(ctx, containerID)
|
owner := getOwnerByID(ctx, containerID)
|
||||||
|
if owner == nil {
|
||||||
|
panic(NotFoundError)
|
||||||
|
}
|
||||||
|
return owner
|
||||||
}
|
}
|
||||||
|
|
||||||
// List method returns list of all container IDs owned by specified owner.
|
// List method returns list of all container IDs owned by specified owner.
|
||||||
|
@ -384,6 +401,8 @@ func List(owner []byte) [][]byte {
|
||||||
// PublicKey contains public key of the signer.
|
// PublicKey contains public key of the signer.
|
||||||
// Token is optional and should be stable marshaled SessionToken structure from
|
// Token is optional and should be stable marshaled SessionToken structure from
|
||||||
// API.
|
// API.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) {
|
func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
|
notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool)
|
||||||
|
@ -394,8 +413,8 @@ func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicK
|
||||||
containerID := eACL[offset : offset+32]
|
containerID := eACL[offset : offset+32]
|
||||||
|
|
||||||
ownerID := getOwnerByID(ctx, containerID)
|
ownerID := getOwnerByID(ctx, containerID)
|
||||||
if len(ownerID) == 0 {
|
if ownerID == nil {
|
||||||
panic("container does not exist")
|
panic(NotFoundError)
|
||||||
}
|
}
|
||||||
|
|
||||||
if notaryDisabled {
|
if notaryDisabled {
|
||||||
|
@ -439,12 +458,14 @@ func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicK
|
||||||
// EACL method returns structure that contains stable marshaled EACLTable structure,
|
// EACL method returns structure that contains stable marshaled EACLTable structure,
|
||||||
// signature, public key of the extended ACL setter and stable marshaled SessionToken
|
// signature, public key of the extended ACL setter and stable marshaled SessionToken
|
||||||
// structure if it was provided.
|
// structure if it was provided.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func EACL(containerID []byte) ExtendedACL {
|
func EACL(containerID []byte) ExtendedACL {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
|
|
||||||
ownerID := getOwnerByID(ctx, containerID)
|
ownerID := getOwnerByID(ctx, containerID)
|
||||||
if len(ownerID) == 0 {
|
if ownerID == nil {
|
||||||
panic("container does not exist")
|
panic(NotFoundError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getEACL(ctx, containerID)
|
return getEACL(ctx, containerID)
|
||||||
|
@ -453,9 +474,15 @@ func EACL(containerID []byte) ExtendedACL {
|
||||||
// PutContainerSize method saves container size estimation in contract
|
// PutContainerSize method saves container size estimation in contract
|
||||||
// memory. Can be invoked only by Storage nodes from the network map. Method
|
// memory. Can be invoked only by Storage nodes from the network map. Method
|
||||||
// checks witness based on the provided public key of the Storage node.
|
// checks witness based on the provided public key of the Storage node.
|
||||||
|
//
|
||||||
|
// If a container doesn't exist it panics with NotFoundError.
|
||||||
func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.PublicKey) {
|
func PutContainerSize(epoch int, cid []byte, usedSize int, pubKey interop.PublicKey) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
|
if getOwnerByID(ctx, cid) == nil {
|
||||||
|
panic(NotFoundError)
|
||||||
|
}
|
||||||
|
|
||||||
if !runtime.CheckWitness(pubKey) {
|
if !runtime.CheckWitness(pubKey) {
|
||||||
panic("invalid witness of container size estimation")
|
panic("invalid witness of container size estimation")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package tests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mr-tron/base58"
|
"github.com/mr-tron/base58"
|
||||||
|
@ -185,11 +186,62 @@ func TestContainerDelete(t *testing.T) {
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, acc, h, "get", c.id[:])
|
tx = PrepareInvoke(t, bc, acc, h, "get", c.id[:])
|
||||||
|
_, err := TestInvoke(bc, tx)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), container.NotFoundError))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerOwner(t *testing.T) {
|
||||||
|
bc := NewChain(t)
|
||||||
|
h, balanceHash := prepareContainerContract(t, bc)
|
||||||
|
|
||||||
|
acc := NewAccount(t, bc)
|
||||||
|
balanceMint(t, bc, acc, balanceHash, containerFee*1, []byte{})
|
||||||
|
|
||||||
|
c := dummyContainer(acc)
|
||||||
|
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", c.value, c.sig, c.pub, c.token)
|
||||||
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
|
t.Run("missing container", func(t *testing.T) {
|
||||||
|
id := c.id
|
||||||
|
id[0] ^= 0xFF
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "owner", id[:])
|
||||||
|
_, err := TestInvoke(bc, tx)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), container.NotFoundError))
|
||||||
|
})
|
||||||
|
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "owner", c.id[:])
|
||||||
|
owner, _ := base58.Decode(acc.Address)
|
||||||
|
CheckTestInvoke(t, bc, tx, stackitem.NewBuffer(owner))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerGet(t *testing.T) {
|
||||||
|
bc := NewChain(t)
|
||||||
|
h, balanceHash := prepareContainerContract(t, bc)
|
||||||
|
|
||||||
|
acc := NewAccount(t, bc)
|
||||||
|
balanceMint(t, bc, acc, balanceHash, containerFee*1, []byte{})
|
||||||
|
|
||||||
|
c := dummyContainer(acc)
|
||||||
|
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", c.value, c.sig, c.pub, c.token)
|
||||||
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
|
t.Run("missing container", func(t *testing.T) {
|
||||||
|
id := c.id
|
||||||
|
id[0] ^= 0xFF
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "get", id[:])
|
||||||
|
_, err := TestInvoke(bc, tx)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), container.NotFoundError))
|
||||||
|
})
|
||||||
|
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "get", c.id[:])
|
||||||
CheckTestInvoke(t, bc, tx, stackitem.NewStruct([]stackitem.Item{
|
CheckTestInvoke(t, bc, tx, stackitem.NewStruct([]stackitem.Item{
|
||||||
stackitem.NewBuffer([]byte{}),
|
stackitem.NewByteArray(c.value),
|
||||||
stackitem.NewBuffer([]byte{}),
|
stackitem.NewByteArray(c.sig),
|
||||||
stackitem.NewBuffer([]byte{}),
|
stackitem.NewByteArray(c.pub),
|
||||||
stackitem.NewBuffer([]byte{}),
|
stackitem.NewByteArray(c.token),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +274,16 @@ func TestContainerSetEACL(t *testing.T) {
|
||||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", c.value, c.sig, c.pub, c.token)
|
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", c.value, c.sig, c.pub, c.token)
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
|
t.Run("missing container", func(t *testing.T) {
|
||||||
|
id := c.id
|
||||||
|
id[0] ^= 0xFF
|
||||||
|
e := dummyEACL(id)
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "setEACL", e.value, e.sig, e.pub, e.token)
|
||||||
|
_, err := TestInvoke(bc, tx)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), container.NotFoundError))
|
||||||
|
})
|
||||||
|
|
||||||
e := dummyEACL(c.id)
|
e := dummyEACL(c.id)
|
||||||
tx = PrepareInvoke(t, bc, acc, h, "setEACL", e.value, e.sig, e.pub, e.token)
|
tx = PrepareInvoke(t, bc, acc, h, "setEACL", e.value, e.sig, e.pub, e.token)
|
||||||
AddBlock(t, bc, tx)
|
AddBlock(t, bc, tx)
|
||||||
|
|
Loading…
Reference in a new issue