manifest: make default trusts invalid

Refs. #3522. The core problem is the same as for groups/features: we can't
allow empty trusts when they're unmarshalled from JSON. But unlike others we
can't easily differentiate missing any value with other cases because the
default value for WildPermissionDescs is a valid thing. Adding an additional
field makes it invalid and we can build around it. Other options are
implementing custom UnmarshalJSON for Manifest (too much for this) or making
Trusts a pointer (an option, but can fail in too many ways).

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2024-07-26 12:32:49 +03:00
parent 58ab24efdb
commit b10af1ed31
7 changed files with 27 additions and 5 deletions

View file

@ -715,6 +715,7 @@ func TestSystemRuntimeNotify_HFBasilisk(t *testing.T) {
Name: "ctr",
Features: json.RawMessage("{}"),
Groups: []manifest.Group{},
Trusts: manifest.WildPermissionDescs{Wildcard: true},
ABI: manifest.ABI{
Methods: []manifest.Method{
{

View file

@ -55,6 +55,7 @@ func TestManagement_DeployUpdate_HFBasilisk(t *testing.T) {
Name: "ctr",
Features: json.RawMessage("{}"),
Groups: []manifest.Group{},
Trusts: manifest.WildPermissionDescs{Wildcard: true},
ABI: manifest.ABI{
Methods: []manifest.Method{
{
@ -92,6 +93,7 @@ func TestManagement_CallInTheSameBlock(t *testing.T) {
Name: "ctr",
Features: json.RawMessage("{}"),
Groups: []manifest.Group{},
Trusts: manifest.WildPermissionDescs{Wildcard: true},
ABI: manifest.ABI{
Methods: []manifest.Method{
{

View file

@ -58,6 +58,7 @@ func TestContractStateToFromSI(t *testing.T) {
t.Run("preserve wildcard trusts", func(t *testing.T) {
contract.Manifest.Trusts.Value = nil
contract.Manifest.Trusts.Wildcard = true
require.True(t, contract.Manifest.Trusts.IsWildcard())
actual := new(Contract)
item, err := contract.ToStackItem()

View file

@ -17,6 +17,7 @@ type WildStrings struct {
// WildPermissionDescs represents a PermissionDescriptor set which can be a wildcard.
type WildPermissionDescs struct {
Value []PermissionDesc
Wildcard bool
}
// Contains checks if v is in the container.
@ -49,13 +50,16 @@ func (c *WildPermissionDescs) Contains(v PermissionDesc) bool {
func (c *WildStrings) IsWildcard() bool { return c.Value == nil }
// IsWildcard returns true iff the container is a wildcard.
func (c *WildPermissionDescs) IsWildcard() bool { return c.Value == nil }
func (c *WildPermissionDescs) IsWildcard() bool { return c.Wildcard }
// Restrict transforms the container into an empty one.
func (c *WildStrings) Restrict() { c.Value = []string{} }
// Restrict transforms the container into an empty one.
func (c *WildPermissionDescs) Restrict() { c.Value = []PermissionDesc{} }
func (c *WildPermissionDescs) Restrict() {
c.Value = []PermissionDesc{}
c.Wildcard = false
}
// Add adds v to the container.
func (c *WildStrings) Add(v string) { c.Value = append(c.Value, v) }
@ -93,7 +97,8 @@ func (c *WildStrings) UnmarshalJSON(data []byte) error {
// UnmarshalJSON implements the json.Unmarshaler interface.
func (c *WildPermissionDescs) UnmarshalJSON(data []byte) error {
if !bytes.Equal(data, []byte(`"*"`)) {
c.Wildcard = bytes.Equal(data, []byte(`"*"`))
if !c.Wildcard {
us := []PermissionDesc{}
if err := json.Unmarshal(data, &us); err != nil {
return err

View file

@ -24,6 +24,9 @@ func TestContainer_Restrict(t *testing.T) {
t.Run("PermissionDesc", func(t *testing.T) {
check := func(t *testing.T, u PermissionDesc) {
c := new(WildPermissionDescs)
require.False(t, c.IsWildcard())
require.False(t, c.Contains(u))
c.Wildcard = true
require.True(t, c.IsWildcard())
require.True(t, c.Contains(u))
c.Restrict()

View file

@ -124,6 +124,9 @@ func (m *Manifest) IsValid(hash util.Uint160, checkSize bool) error {
if err != nil {
return err
}
if m.Trusts.Value == nil && !m.Trusts.Wildcard {
return errors.New("invalid (null?) trusts")
}
if len(m.Trusts.Value) > 1 {
hashes := make([]PermissionDesc, len(m.Trusts.Value))
copy(hashes, m.Trusts.Value)
@ -278,7 +281,7 @@ func (m *Manifest) FromStackItem(item stackitem.Item) error {
m.Permissions[i] = *p
}
if _, ok := str[6].(stackitem.Null); ok {
m.Trusts = WildPermissionDescs{Value: nil} // wildcard by default
m.Trusts = WildPermissionDescs{Value: nil, Wildcard: true} // wildcard by default
} else {
if str[6].Type() != stackitem.ArrayT {
return errors.New("invalid Trusts stackitem type")

View file

@ -212,6 +212,13 @@ func TestIsValid(t *testing.T) {
})
m.SupportedStandards = m.SupportedStandards[:1]
t.Run("invalid, no trusts", func(t *testing.T) {
m.Trusts.Value = nil
m.Trusts.Wildcard = false
require.Error(t, m.IsValid(contractHash, true))
})
m.Trusts.Restrict()
d := PermissionDesc{Type: PermissionHash, Value: util.Uint160{1, 2, 3}}
m.Trusts.Add(d)
t.Run("valid, with trust", func(t *testing.T) {