github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/smartcontract/manifest/permission_test.go (about) 1 package manifest 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "reflect" 7 "testing" 8 9 "github.com/nspcc-dev/neo-go/internal/random" 10 "github.com/nspcc-dev/neo-go/pkg/crypto/keys" 11 "github.com/nspcc-dev/neo-go/pkg/util" 12 "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestNewPermission(t *testing.T) { 17 require.Panics(t, func() { NewPermission(PermissionWildcard, util.Uint160{}) }) 18 require.Panics(t, func() { NewPermission(PermissionHash) }) 19 require.Panics(t, func() { NewPermission(PermissionHash, 1) }) 20 require.Panics(t, func() { NewPermission(PermissionGroup) }) 21 require.Panics(t, func() { NewPermission(PermissionGroup, util.Uint160{}) }) 22 } 23 24 func TestPermissionIsValid(t *testing.T) { 25 p := Permission{} 26 require.NoError(t, p.IsValid()) 27 28 p.Methods.Add("") 29 require.Error(t, p.IsValid()) 30 31 p.Methods.Value = nil 32 p.Methods.Add("qwerty") 33 require.NoError(t, p.IsValid()) 34 35 p.Methods.Add("poiuyt") 36 require.NoError(t, p.IsValid()) 37 38 p.Methods.Add("qwerty") 39 require.Error(t, p.IsValid()) 40 } 41 42 func TestPermissionsAreValid(t *testing.T) { 43 p := Permissions{} 44 require.NoError(t, p.AreValid()) 45 46 p = append(p, Permission{Methods: WildStrings{Value: []string{""}}}) 47 require.Error(t, p.AreValid()) 48 49 p = p[:0] 50 p = append(p, *NewPermission(PermissionHash, util.Uint160{1, 2, 3})) 51 require.NoError(t, p.AreValid()) 52 53 priv0, err := keys.NewPrivateKey() 54 require.NoError(t, err) 55 priv1, err := keys.NewPrivateKey() 56 require.NoError(t, err) 57 58 p = append(p, *NewPermission(PermissionGroup, priv0.PublicKey())) 59 require.NoError(t, p.AreValid()) 60 61 p = append(p, *NewPermission(PermissionGroup, priv1.PublicKey())) 62 require.NoError(t, p.AreValid()) 63 64 p = append(p, *NewPermission(PermissionWildcard)) 65 require.NoError(t, p.AreValid()) 66 67 p = append(p, *NewPermission(PermissionHash, util.Uint160{3, 2, 1})) 68 require.NoError(t, p.AreValid()) 69 70 p = append(p, *NewPermission(PermissionWildcard)) 71 require.Error(t, p.AreValid()) 72 73 p = append(p[:len(p)-1], *NewPermission(PermissionHash, util.Uint160{1, 2, 3})) 74 require.Error(t, p.AreValid()) 75 76 p = append(p[:len(p)-1], *NewPermission(PermissionGroup, priv0.PublicKey())) 77 require.Error(t, p.AreValid()) 78 } 79 80 func TestPermission_MarshalJSON(t *testing.T) { 81 t.Run("wildcard", func(t *testing.T) { 82 expected := NewPermission(PermissionWildcard) 83 expected.Methods.Restrict() 84 testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard)) 85 }) 86 87 t.Run("group", func(t *testing.T) { 88 expected := NewPermission(PermissionWildcard) 89 expected.Contract.Type = PermissionGroup 90 priv, err := keys.NewPrivateKey() 91 require.NoError(t, err) 92 expected.Contract.Value = priv.PublicKey() 93 expected.Methods.Add("method1") 94 expected.Methods.Add("method2") 95 testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard)) 96 }) 97 98 t.Run("hash", func(t *testing.T) { 99 expected := NewPermission(PermissionWildcard) 100 expected.Contract.Type = PermissionHash 101 expected.Contract.Value = random.Uint160() 102 testMarshalUnmarshal(t, expected, NewPermission(PermissionWildcard)) 103 }) 104 } 105 106 func TestPermissionDesc_MarshalJSON(t *testing.T) { 107 t.Run("uint160 with 0x", func(t *testing.T) { 108 u := random.Uint160() 109 s := u.StringLE() 110 js := []byte(fmt.Sprintf(`"0x%s"`, s)) 111 d := new(PermissionDesc) 112 require.NoError(t, json.Unmarshal(js, d)) 113 require.Equal(t, u, d.Value.(util.Uint160)) 114 }) 115 116 t.Run("invalid uint160", func(t *testing.T) { 117 d := new(PermissionDesc) 118 s := random.String(util.Uint160Size * 2) 119 js := []byte(fmt.Sprintf(`"ok%s"`, s)) 120 require.Error(t, json.Unmarshal(js, d)) 121 122 js = []byte(fmt.Sprintf(`"%s"`, s)) 123 require.Error(t, json.Unmarshal(js, d)) 124 }) 125 126 t.Run("invalid public key", func(t *testing.T) { 127 d := new(PermissionDesc) 128 s := random.String(65) 129 s = "k" + s // not a hex 130 js := []byte(fmt.Sprintf(`"%s"`, s)) 131 require.Error(t, json.Unmarshal(js, d)) 132 }) 133 134 t.Run("not a string", func(t *testing.T) { 135 d := new(PermissionDesc) 136 js := []byte(`123`) 137 require.Error(t, json.Unmarshal(js, d)) 138 }) 139 140 t.Run("invalid string", func(t *testing.T) { 141 d := new(PermissionDesc) 142 js := []byte(`"invalid length"`) 143 require.Error(t, json.Unmarshal(js, d)) 144 }) 145 } 146 147 func testMarshalUnmarshal(t *testing.T, expected, actual any) { 148 data, err := json.Marshal(expected) 149 require.NoError(t, err) 150 require.NoError(t, json.Unmarshal(data, actual)) 151 require.Equal(t, expected, actual) 152 } 153 154 func TestPermission_ToStackItemFromStackItem(t *testing.T) { 155 t.Run("wildcard", func(t *testing.T) { 156 p := NewPermission(PermissionWildcard) 157 expected := stackitem.NewStruct([]stackitem.Item{ 158 stackitem.Null{}, 159 stackitem.Null{}, 160 }) 161 CheckToFromStackItem(t, p, expected) 162 }) 163 164 t.Run("hash", func(t *testing.T) { 165 p := NewPermission(PermissionHash, util.Uint160{1, 2, 3}) 166 p.Methods = WildStrings{Value: []string{"a"}} 167 expected := stackitem.NewStruct([]stackitem.Item{ 168 stackitem.NewByteArray(util.Uint160{1, 2, 3}.BytesBE()), 169 stackitem.NewArray([]stackitem.Item{ 170 stackitem.NewByteArray([]byte("a")), 171 }), 172 }) 173 CheckToFromStackItem(t, p, expected) 174 }) 175 176 t.Run("group", func(t *testing.T) { 177 pk, _ := keys.NewPrivateKey() 178 p := NewPermission(PermissionGroup, pk.PublicKey()) 179 expected := stackitem.NewStruct([]stackitem.Item{ 180 stackitem.NewByteArray(pk.PublicKey().Bytes()), 181 stackitem.Null{}, 182 }) 183 CheckToFromStackItem(t, p, expected) 184 }) 185 } 186 187 type Interoperable interface { 188 ToStackItem() stackitem.Item 189 FromStackItem(stackitem.Item) error 190 } 191 192 func CheckToFromStackItem(t *testing.T, source Interoperable, expected stackitem.Item) { 193 actual := source.ToStackItem() 194 require.Equal(t, expected, actual) 195 actualSource := reflect.New(reflect.TypeOf(source).Elem()).Interface().(Interoperable) 196 require.NoError(t, actualSource.FromStackItem(actual)) 197 require.Equal(t, source, actualSource) 198 } 199 200 func TestPermission_FromStackItemErrors(t *testing.T) { 201 errCases := map[string]stackitem.Item{ 202 "not a struct": stackitem.NewArray([]stackitem.Item{}), 203 "invalid length": stackitem.NewStruct([]stackitem.Item{}), 204 "invalid contract type": stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.NewBool(false)}), 205 "invalid contract length": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray([]byte{1, 2, 3}), stackitem.NewBool(false)}), 206 "invalid contract pubkey": stackitem.NewStruct([]stackitem.Item{stackitem.NewByteArray(make([]byte, 33)), stackitem.NewBool(false)}), 207 "invalid methods type": stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewBool(false)}), 208 "invalid method name": stackitem.NewStruct([]stackitem.Item{stackitem.Null{}, stackitem.NewArray([]stackitem.Item{stackitem.NewArray([]stackitem.Item{})})}), 209 } 210 for name, errCase := range errCases { 211 t.Run(name, func(t *testing.T) { 212 p := new(Permission) 213 require.Error(t, p.FromStackItem(errCase)) 214 }) 215 } 216 }