github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/smartcontract/manifest/manifest_test.go (about)

     1  package manifest
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"math/big"
     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/smartcontract"
    12  	"github.com/nspcc-dev/neo-go/pkg/util"
    13  	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  // Test vectors are taken from the main NEO repo
    18  // https://github.com/neo-project/neo/blob/master/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs#L10
    19  func TestManifest_MarshalJSON(t *testing.T) {
    20  	t.Run("default", func(t *testing.T) {
    21  		s := `{"groups":[],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
    22  		m := testUnmarshalMarshalManifest(t, s)
    23  		require.Equal(t, DefaultManifest("Test"), m)
    24  	})
    25  
    26  	t.Run("permissions", func(t *testing.T) {
    27  		s := `{"groups":[],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"0x0000000000000000000000000000000000000000","methods":["method1","method2"]}],"trusts":[],"extra":null}`
    28  		testUnmarshalMarshalManifest(t, s)
    29  	})
    30  
    31  	t.Run("safe methods", func(t *testing.T) {
    32  		s := `{"groups":[],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[{"name":"safeMet","offset":123,"parameters":[],"returntype":"Integer","safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
    33  		testUnmarshalMarshalManifest(t, s)
    34  	})
    35  
    36  	t.Run("trust", func(t *testing.T) {
    37  		s := `{"groups":[],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":["0x0000000000000000000000000000000000000001"],"extra":null}`
    38  		testUnmarshalMarshalManifest(t, s)
    39  	})
    40  
    41  	t.Run("groups", func(t *testing.T) {
    42  		s := `{"groups":[{"pubkey":"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c","signature":"QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=="}],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}`
    43  		testUnmarshalMarshalManifest(t, s)
    44  	})
    45  
    46  	t.Run("extra", func(t *testing.T) {
    47  		s := `{"groups":[],"features":{},"supportedstandards":[],"name":"Test","abi":{"methods":[],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"key":"value"}}`
    48  		testUnmarshalMarshalManifest(t, s)
    49  	})
    50  }
    51  
    52  func testUnmarshalMarshalManifest(t *testing.T, s string) *Manifest {
    53  	js := []byte(s)
    54  	c := NewManifest("Test")
    55  	require.NoError(t, json.Unmarshal(js, c))
    56  
    57  	data, err := json.Marshal(c)
    58  	require.NoError(t, err)
    59  	require.JSONEq(t, s, string(data))
    60  
    61  	return c
    62  }
    63  
    64  func TestManifest_CanCall(t *testing.T) {
    65  	man1 := DefaultManifest("Test1")
    66  	man2 := DefaultManifest("Test2")
    67  	require.True(t, man1.CanCall(util.Uint160{}, man2, "method1"))
    68  }
    69  
    70  func TestPermission_IsAllowed(t *testing.T) {
    71  	manifest := DefaultManifest("Test")
    72  
    73  	t.Run("wildcard", func(t *testing.T) {
    74  		h := random.Uint160()
    75  
    76  		perm := NewPermission(PermissionWildcard)
    77  		require.True(t, perm.IsAllowed(h, manifest, "AAA"))
    78  
    79  		perm.Methods.Restrict()
    80  		require.False(t, perm.IsAllowed(h, manifest, "AAA"))
    81  
    82  		perm.Methods.Add("AAA")
    83  		require.True(t, perm.IsAllowed(h, manifest, "AAA"))
    84  	})
    85  
    86  	t.Run("hash", func(t *testing.T) {
    87  		perm := NewPermission(PermissionHash, util.Uint160{})
    88  		require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
    89  
    90  		t.Run("restrict methods", func(t *testing.T) {
    91  			perm.Methods.Restrict()
    92  			require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
    93  			perm.Methods.Add("AAA")
    94  			require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
    95  		})
    96  	})
    97  
    98  	t.Run("invalid hash", func(t *testing.T) {
    99  		perm := NewPermission(PermissionHash, util.Uint160{1})
   100  		require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
   101  	})
   102  
   103  	priv, err := keys.NewPrivateKey()
   104  	require.NoError(t, err)
   105  	manifest.Groups = []Group{{PublicKey: priv.PublicKey()}}
   106  
   107  	t.Run("group", func(t *testing.T) {
   108  		perm := NewPermission(PermissionGroup, priv.PublicKey())
   109  		require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
   110  
   111  		priv2, err := keys.NewPrivateKey()
   112  		require.NoError(t, err)
   113  
   114  		perm = NewPermission(PermissionGroup, priv2.PublicKey())
   115  		require.False(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
   116  
   117  		manifest.Groups = append(manifest.Groups, Group{PublicKey: priv2.PublicKey()})
   118  		perm = NewPermission(PermissionGroup, priv2.PublicKey())
   119  		require.True(t, perm.IsAllowed(util.Uint160{}, manifest, "AAA"))
   120  	})
   121  }
   122  
   123  func TestIsValid(t *testing.T) {
   124  	contractHash := util.Uint160{1, 2, 3}
   125  	m := &Manifest{}
   126  
   127  	t.Run("invalid, no name", func(t *testing.T) {
   128  		require.Error(t, m.IsValid(contractHash, true))
   129  	})
   130  
   131  	m = NewManifest("Test")
   132  
   133  	t.Run("invalid, no ABI methods", func(t *testing.T) {
   134  		require.Error(t, m.IsValid(contractHash, true))
   135  	})
   136  
   137  	m.ABI.Methods = append(m.ABI.Methods, Method{
   138  		Name:       "dummy",
   139  		ReturnType: smartcontract.VoidType,
   140  		Parameters: []Parameter{},
   141  	})
   142  
   143  	t.Run("valid, no groups/events", func(t *testing.T) {
   144  		require.NoError(t, m.IsValid(contractHash, true))
   145  	})
   146  
   147  	m.ABI.Events = append(m.ABI.Events, Event{
   148  		Name:       "itHappened",
   149  		Parameters: []Parameter{},
   150  	})
   151  
   152  	t.Run("valid, with events", func(t *testing.T) {
   153  		require.NoError(t, m.IsValid(contractHash, true))
   154  	})
   155  
   156  	m.ABI.Events = append(m.ABI.Events, Event{
   157  		Name: "itHappened",
   158  		Parameters: []Parameter{
   159  			NewParameter("qwerty", smartcontract.IntegerType),
   160  			NewParameter("qwerty", smartcontract.IntegerType),
   161  		},
   162  	})
   163  
   164  	t.Run("invalid, bad event", func(t *testing.T) {
   165  		require.Error(t, m.IsValid(contractHash, true))
   166  	})
   167  	m.ABI.Events = m.ABI.Events[:1]
   168  
   169  	m.Permissions = append(m.Permissions, *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
   170  	t.Run("valid, with permissions", func(t *testing.T) {
   171  		require.NoError(t, m.IsValid(contractHash, true))
   172  	})
   173  
   174  	m.Permissions = append(m.Permissions, *NewPermission(PermissionHash, util.Uint160{1, 2, 3}))
   175  	t.Run("invalid, with permissions", func(t *testing.T) {
   176  		require.Error(t, m.IsValid(contractHash, true))
   177  	})
   178  	m.Permissions = m.Permissions[:1]
   179  
   180  	m.SupportedStandards = append(m.SupportedStandards, "NEP-17")
   181  	t.Run("valid, with standards", func(t *testing.T) {
   182  		require.NoError(t, m.IsValid(contractHash, true))
   183  	})
   184  
   185  	m.SupportedStandards = append(m.SupportedStandards, "")
   186  	t.Run("invalid, with nameless standard", func(t *testing.T) {
   187  		require.Error(t, m.IsValid(contractHash, true))
   188  	})
   189  	m.SupportedStandards = m.SupportedStandards[:1]
   190  
   191  	m.SupportedStandards = append(m.SupportedStandards, "NEP-17")
   192  	t.Run("invalid, with duplicate standards", func(t *testing.T) {
   193  		require.Error(t, m.IsValid(contractHash, true))
   194  	})
   195  	m.SupportedStandards = m.SupportedStandards[:1]
   196  
   197  	d := PermissionDesc{Type: PermissionHash, Value: util.Uint160{1, 2, 3}}
   198  	m.Trusts.Add(d)
   199  	t.Run("valid, with trust", func(t *testing.T) {
   200  		require.NoError(t, m.IsValid(contractHash, true))
   201  	})
   202  
   203  	m.Trusts.Add(PermissionDesc{Type: PermissionHash, Value: util.Uint160{3, 2, 1}})
   204  	t.Run("valid, with trusts", func(t *testing.T) {
   205  		require.NoError(t, m.IsValid(contractHash, true))
   206  	})
   207  
   208  	m.Trusts.Add(d)
   209  	t.Run("invalid, with trusts", func(t *testing.T) {
   210  		require.Error(t, m.IsValid(contractHash, true))
   211  	})
   212  	m.Trusts.Restrict()
   213  
   214  	t.Run("with groups", func(t *testing.T) {
   215  		m.Groups = make([]Group, 3)
   216  		pks := make([]*keys.PrivateKey, 3)
   217  		for i := range pks {
   218  			pk, err := keys.NewPrivateKey()
   219  			require.NoError(t, err)
   220  			pks[i] = pk
   221  			m.Groups[i] = Group{
   222  				PublicKey: pk.PublicKey(),
   223  				Signature: pk.Sign(contractHash.BytesBE()),
   224  			}
   225  		}
   226  
   227  		t.Run("valid", func(t *testing.T) {
   228  			require.NoError(t, m.IsValid(contractHash, true))
   229  		})
   230  
   231  		t.Run("invalid, wrong contract hash", func(t *testing.T) {
   232  			require.Error(t, m.IsValid(util.Uint160{4, 5, 6}, true))
   233  		})
   234  
   235  		t.Run("invalid, wrong group signature", func(t *testing.T) {
   236  			pk, err := keys.NewPrivateKey()
   237  			require.NoError(t, err)
   238  			m.Groups = append(m.Groups, Group{
   239  				PublicKey: pk.PublicKey(),
   240  				// actually, there shouldn't be such situation, as Signature is always the signature
   241  				// of the contract hash.
   242  				Signature: pk.Sign([]byte{1, 2, 3}),
   243  			})
   244  			require.Error(t, m.IsValid(contractHash, true))
   245  		})
   246  	})
   247  	m.Groups = m.Groups[:0]
   248  
   249  	t.Run("invalid, unserializable", func(t *testing.T) {
   250  		for i := 0; i < stackitem.MaxSerialized; i++ {
   251  			m.ABI.Events = append(m.ABI.Events, Event{
   252  				Name:       fmt.Sprintf("Event%d", i),
   253  				Parameters: []Parameter{},
   254  			})
   255  		}
   256  		err := m.IsValid(contractHash, true)
   257  		require.ErrorIs(t, err, stackitem.ErrTooBig)
   258  	})
   259  }
   260  
   261  func TestManifestToStackItem(t *testing.T) {
   262  	check := func(t *testing.T, expected *Manifest) {
   263  		item, err := expected.ToStackItem()
   264  		require.NoError(t, err)
   265  		actual := new(Manifest)
   266  		require.NoError(t, actual.FromStackItem(item))
   267  		require.Equal(t, expected, actual)
   268  	}
   269  
   270  	t.Run("default", func(t *testing.T) {
   271  		expected := DefaultManifest("manifest")
   272  		check(t, expected)
   273  	})
   274  
   275  	t.Run("full", func(t *testing.T) {
   276  		pk, _ := keys.NewPrivateKey()
   277  		expected := &Manifest{
   278  			Name: "manifest",
   279  			ABI: ABI{
   280  				Methods: []Method{{
   281  					Name:   "method",
   282  					Offset: 15,
   283  					Parameters: []Parameter{{
   284  						Name: "param",
   285  						Type: smartcontract.StringType,
   286  					}},
   287  					ReturnType: smartcontract.BoolType,
   288  					Safe:       true,
   289  				}},
   290  				Events: []Event{{
   291  					Name: "event",
   292  					Parameters: []Parameter{{
   293  						Name: "param",
   294  						Type: smartcontract.BoolType,
   295  					}},
   296  				}},
   297  			},
   298  			Features: json.RawMessage("{}"),
   299  			Groups: []Group{{
   300  				PublicKey: pk.PublicKey(),
   301  				Signature: make([]byte, keys.SignatureLen),
   302  			}},
   303  			Permissions:        []Permission{*NewPermission(PermissionWildcard)},
   304  			SupportedStandards: []string{"NEP-17"},
   305  			Trusts: WildPermissionDescs{
   306  				Value: []PermissionDesc{
   307  					{
   308  						Type:  PermissionHash,
   309  						Value: util.Uint160{1, 2, 3},
   310  					},
   311  					{
   312  						Type:  PermissionGroup,
   313  						Value: pk.PublicKey(),
   314  					},
   315  				},
   316  			},
   317  			Extra: []byte(`"even string allowed"`),
   318  		}
   319  		check(t, expected)
   320  	})
   321  
   322  	t.Run("compat", func(t *testing.T) {
   323  		// Compatibility test with NeoC#, see https://github.com/neo-project/neo/pull/2948.
   324  		var mJSON = `{"name":"CallOracleContract-6","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"request","parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","offset":0,"safe":false},{"name":"callback","parameters":[{"name":"url","type":"String"},{"name":"userData","type":"Any"},{"name":"responseCode","type":"Integer"},{"name":"response","type":"ByteArray"}],"returntype":"Void","offset":86,"safe":false},{"name":"getStoredUrl","parameters":[],"returntype":"String","offset":129,"safe":false},{"name":"getStoredResponseCode","parameters":[],"returntype":"Integer","offset":142,"safe":false},{"name":"getStoredResponse","parameters":[],"returntype":"ByteArray","offset":165,"safe":false}],"events":[]},"permissions":[{"contract":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","methods":"*"},{"contract":"*","methods":"*"}],"trusts":["0xfe924b7cfe89ddd271abaf7210a80a7e11178758","*"],"extra":{}}`
   325  		c := NewManifest("Test")
   326  		require.NoError(t, json.Unmarshal([]byte(mJSON), c))
   327  
   328  		si, err := c.ToStackItem()
   329  		require.NoError(t, err)
   330  		actual := new(Manifest)
   331  		require.NoError(t, actual.FromStackItem(si))
   332  		require.NotEqual(t, actual.Permissions[0].Contract.Type, PermissionWildcard)
   333  		require.True(t, actual.Permissions[0].Methods.IsWildcard())
   334  		require.Equal(t, actual.Permissions[1].Contract.Type, PermissionWildcard)
   335  		require.True(t, actual.Permissions[1].Methods.IsWildcard())
   336  
   337  		require.NotEqual(t, actual.Trusts.Value[0].Type, PermissionWildcard)
   338  		require.Equal(t, actual.Trusts.Value[1].Type, PermissionWildcard)
   339  	})
   340  }
   341  
   342  func TestManifest_FromStackItemErrors(t *testing.T) {
   343  	name := stackitem.NewByteArray([]byte{})
   344  	groups := stackitem.NewArray([]stackitem.Item{})
   345  	features := stackitem.NewMap()
   346  	sStandards := stackitem.NewArray([]stackitem.Item{})
   347  	abi := stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.NewArray([]stackitem.Item{})})
   348  	permissions := stackitem.NewArray([]stackitem.Item{})
   349  	trusts := stackitem.NewArray([]stackitem.Item{})
   350  	extra := stackitem.NewByteArray([]byte{})
   351  
   352  	// check OK
   353  	goodSI := []stackitem.Item{name, groups, features, sStandards, abi, permissions, trusts, extra}
   354  	m := new(Manifest)
   355  	require.NoError(t, m.FromStackItem(stackitem.NewStruct(goodSI)))
   356  
   357  	errCases := map[string]stackitem.Item{
   358  		"not a struct":                     stackitem.NewArray([]stackitem.Item{}),
   359  		"invalid length":                   stackitem.NewStruct([]stackitem.Item{}),
   360  		"invalid name type":                stackitem.NewStruct(append([]stackitem.Item{stackitem.NewInterop(nil)}, goodSI[1:]...)),
   361  		"invalid Groups type":              stackitem.NewStruct(append([]stackitem.Item{name, stackitem.Null{}}, goodSI[2:]...)),
   362  		"invalid group":                    stackitem.NewStruct(append([]stackitem.Item{name, stackitem.NewArray([]stackitem.Item{stackitem.Null{}})}, goodSI[2:]...)),
   363  		"invalid Features type":            stackitem.NewStruct(append([]stackitem.Item{name, groups, stackitem.Null{}}, goodSI[3:]...)),
   364  		"invalid supported standards type": stackitem.NewStruct(append([]stackitem.Item{name, groups, features, stackitem.Null{}}, goodSI[4:]...)),
   365  		"invalid supported standard":       stackitem.NewStruct(append([]stackitem.Item{name, groups, features, stackitem.NewArray([]stackitem.Item{stackitem.Null{}})}, goodSI[4:]...)),
   366  		"invalid ABI":                      stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, stackitem.Null{}}, goodSI[5:]...)),
   367  		"invalid Permissions type":         stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, abi, stackitem.Null{}}, goodSI[6:]...)),
   368  		"invalid permission":               stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, abi, stackitem.NewArray([]stackitem.Item{stackitem.Null{}})}, goodSI[6:]...)),
   369  		"invalid Trusts type":              stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, abi, permissions, stackitem.NewInterop(nil)}, goodSI[7:]...)),
   370  		"invalid trust":                    stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, abi, permissions, stackitem.NewArray([]stackitem.Item{stackitem.NewInterop(nil)})}, goodSI[7:]...)),
   371  		"invalid Uint160 trust":            stackitem.NewStruct(append([]stackitem.Item{name, groups, features, sStandards, abi, permissions, stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte{1, 2, 3})})}, goodSI[7:]...)),
   372  		"invalid extra type":               stackitem.NewStruct([]stackitem.Item{name, groups, features, sStandards, abi, permissions, trusts, stackitem.Null{}}),
   373  	}
   374  	for name, errCase := range errCases {
   375  		t.Run(name, func(t *testing.T) {
   376  			p := new(Manifest)
   377  			require.Error(t, p.FromStackItem(errCase))
   378  		})
   379  	}
   380  }
   381  
   382  func TestABI_ToStackItemFromStackItem(t *testing.T) {
   383  	a := &ABI{
   384  		Methods: []Method{{
   385  			Name:       "mur",
   386  			Offset:     5,
   387  			Parameters: []Parameter{{Name: "p1", Type: smartcontract.BoolType}},
   388  			ReturnType: smartcontract.StringType,
   389  			Safe:       true,
   390  		}},
   391  		Events: []Event{{
   392  			Name:       "mur",
   393  			Parameters: []Parameter{{Name: "p1", Type: smartcontract.BoolType}},
   394  		}},
   395  	}
   396  	expected := stackitem.NewStruct([]stackitem.Item{
   397  		stackitem.NewArray([]stackitem.Item{
   398  			stackitem.NewStruct([]stackitem.Item{
   399  				stackitem.NewByteArray([]byte("mur")),
   400  				stackitem.NewArray([]stackitem.Item{
   401  					stackitem.NewStruct([]stackitem.Item{
   402  						stackitem.NewByteArray([]byte("p1")),
   403  						stackitem.NewBigInteger(big.NewInt(int64(smartcontract.BoolType))),
   404  					}),
   405  				}),
   406  				stackitem.NewBigInteger(big.NewInt(int64(smartcontract.StringType))),
   407  				stackitem.NewBigInteger(big.NewInt(int64(5))),
   408  				stackitem.NewBool(true),
   409  			}),
   410  		}),
   411  		stackitem.NewArray([]stackitem.Item{
   412  			stackitem.NewStruct([]stackitem.Item{
   413  				stackitem.NewByteArray([]byte("mur")),
   414  				stackitem.NewArray([]stackitem.Item{
   415  					stackitem.NewStruct([]stackitem.Item{
   416  						stackitem.NewByteArray([]byte("p1")),
   417  						stackitem.NewBigInteger(big.NewInt(int64(smartcontract.BoolType))),
   418  					}),
   419  				}),
   420  			}),
   421  		}),
   422  	})
   423  	CheckToFromStackItem(t, a, expected)
   424  }
   425  
   426  func TestABI_FromStackItemErrors(t *testing.T) {
   427  	errCases := map[string]stackitem.Item{
   428  		"not a struct":         stackitem.NewArray([]stackitem.Item{}),
   429  		"invalid length":       stackitem.NewStruct([]stackitem.Item{}),
   430  		"invalid methods type": stackitem.NewStruct([]stackitem.Item{stackitem.NewInterop(nil), stackitem.Null{}}),
   431  		"invalid method":       stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{stackitem.Null{}}), stackitem.Null{}}),
   432  		"invalid events type":  stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.Null{}}),
   433  		"invalid event":        stackitem.NewStruct([]stackitem.Item{stackitem.NewArray([]stackitem.Item{}), stackitem.NewArray([]stackitem.Item{stackitem.Null{}})}),
   434  	}
   435  	for name, errCase := range errCases {
   436  		t.Run(name, func(t *testing.T) {
   437  			p := new(ABI)
   438  			require.Error(t, p.FromStackItem(errCase))
   439  		})
   440  	}
   441  }
   442  
   443  func TestExtraToStackItem(t *testing.T) {
   444  	testCases := []struct {
   445  		raw, expected string
   446  	}{
   447  		{"null", "null"},
   448  		{"1", "1"},
   449  		{"1.23456789101112131415", "1.23456789101112131415"},
   450  		{`"string with space"`, `"string with space"`},
   451  		{`{ "a":1, "sss" : {"m" : 1, "a" : 2} , "x"  :  2  ,"c" :3,"z":4,  "s":"5"}`,
   452  			`{"a":1,"sss":{"m":1,"a":2},"x":2,"c":3,"z":4,"s":"5"}`},
   453  		{`  [ 1, "array", { "d": "z", "a":"x",  "c" : "y",  "b":3}]`,
   454  			`[1,"array",{"d":"z","a":"x","c":"y","b":3}]`},
   455  		{
   456  			// C# double quotes marshalling compatibility test, ref. #3284.
   457  			`{"Author":"NEOZEN","Description":"NEO\u0027s First Inscriptions Meta Protocol","Deployment":"{\"p\":\"neoz-20\",\"op\":\"deploy\",\"tick\":\"neoz\",\"max\":\"21000000\",\"lim\":\"1000\"}"}`,
   458  			`{"Author":"NEOZEN","Description":"NEO\u0027s First Inscriptions Meta Protocol","Deployment":"{\u0022p\u0022:\u0022neoz-20\u0022,\u0022op\u0022:\u0022deploy\u0022,\u0022tick\u0022:\u0022neoz\u0022,\u0022max\u0022:\u002221000000\u0022,\u0022lim\u0022:\u00221000\u0022}"}`,
   459  		},
   460  	}
   461  
   462  	for _, tc := range testCases {
   463  		res := extraToStackItem([]byte(tc.raw))
   464  		actual, ok := res.Value().([]byte)
   465  		require.True(t, ok)
   466  		require.Equal(t, tc.expected, string(actual))
   467  	}
   468  }
   469  
   470  func TestManifest_IsStandardSupported(t *testing.T) {
   471  	m := &Manifest{
   472  		SupportedStandards: []string{NEP17StandardName, NEP17Payable, NEP11Payable},
   473  	}
   474  	for _, st := range m.SupportedStandards {
   475  		require.True(t, m.IsStandardSupported(st))
   476  	}
   477  	require.False(t, m.IsStandardSupported(NEP11StandardName))
   478  	require.False(t, m.IsStandardSupported(""))
   479  	require.False(t, m.IsStandardSupported("unknown standard"))
   480  }