github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/rpcsrv/params/tx_builder_test.go (about) 1 package params 2 3 import ( 4 "encoding/base64" 5 "fmt" 6 "math/big" 7 "testing" 8 9 "github.com/nspcc-dev/neo-go/pkg/io" 10 "github.com/nspcc-dev/neo-go/pkg/util" 11 "github.com/nspcc-dev/neo-go/pkg/vm/opcode" 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func TestInvocationScriptCreationGood(t *testing.T) { 17 p := Param{RawMessage: []byte(`"50befd26fdf6e4d957c11e078b24ebce6291456f"`)} 18 contract, err := p.GetUint160FromHex() 19 require.Nil(t, err) 20 21 var paramScripts = []struct { 22 ps Params 23 script string 24 }{{ 25 ps: Params{{RawMessage: []byte(`"transfer"`)}}, 26 script: "wh8MCHRyYW5zZmVyDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS", 27 }, { 28 ps: Params{{RawMessage: []byte(`42`)}}, 29 script: "wh8MAjQyDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS", 30 }, { 31 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[]`)}}, 32 script: "wh8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 33 }, { 34 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "ByteArray", "value": "AwEtR+diEK7HO+Oas9GG4KQP6Nhr+j1Pq/2le6E7iPlq"}]`)}}, 35 script: "DCEDAS1H52IQrsc745qz0YbgpA/o2Gv6PU+r/aV7oTuI+WoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 36 }, { 37 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Signature", "value": "4edf5005771de04619235d5a4c7a9a11bb78e008541f1da7725f654c33380a3c87e2959a025da706d7255cb3a3fa07ebe9c6559d0d9e6213c68049168eb1056f"}]`)}}, 38 script: "DGDh51/nTTnvvV17TjrX3bfl3lrhztr1rXVtvvx7TTznjV/V1rvvbl/rnhzfffzRrdzzt7b3n1rTbl1rvTp3vbnlxvdrd9rTt5t71zrnn13R317rbXdzrzTj3Xrx5vXTnp8RwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 39 }, { 40 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Signature", "value": "Tt9QBXcd4EYZI11aTHqaEbt44AhUHx2ncl9lTDM4CjyH4pWaAl2nBtclXLOj+gfr6cZVnQ2eYhPGgEkWjrEFbw=="}]`)}}, 41 script: "DEBO31AFdx3gRhkjXVpMepoRu3jgCFQfHadyX2VMMzgKPIfilZoCXacG1yVcs6P6B+vpxlWdDZ5iE8aASRaOsQVvEcAfDAFhDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS", 42 }, { 43 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "String", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}]`)}}, 44 script: "DCg1MGJlZmQyNmZkZjZlNGQ5NTdjMTFlMDc4YjI0ZWJjZTYyOTE0NTZmEcAfDAFhDBRvRZFizuskiwcewVfZ5Pb9Jv2+UEFifVtS", 45 }, { 46 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Hash160", "value": "50befd26fdf6e4d957c11e078b24ebce6291456f"}]`)}}, 47 script: "DBRvRZFizuskiwcewVfZ5Pb9Jv2+UBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 48 }, { 49 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Hash256", "value": "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7"}]`)}}, 50 script: "DCDnLShpee5ssbfmXf3fsuOEEAuNFI53WN5C5BaLcXksYBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 51 }, { 52 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "PublicKey", "value": "03c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1"}]`)}}, 53 script: "DCEDwInXEiuECkk1I06C4mrl79DCrLYnI53J8gcxEze28sERwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 54 }, { 55 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": 42}]`)}}, 56 script: "ACoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 57 }, { 58 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": "42"}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params 59 script: "ACoRwB8MAWEMFG9FkWLO6ySLBx7BV9nk9v0m/b5QQWJ9W1I=", 60 }, { 61 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Integer", "value": true}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params 62 script: "ERHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 63 }, { 64 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": true}]`)}}, 65 script: "CBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 66 }, { 67 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": false}]`)}}, 68 script: "CRHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 69 }, { 70 ps: Params{{RawMessage: []byte(`"a"`)}, {RawMessage: []byte(`[{"type": "Boolean", "value": "blah"}]`)}}, // C# code doesn't use strict type assertions for JSON-ised params 71 script: "CBHAHwwBYQwUb0WRYs7rJIsHHsFX2eT2/Sb9vlBBYn1bUg==", 72 }} 73 for i, ps := range paramScripts { 74 method, err := ps.ps[0].GetString() 75 require.NoError(t, err, fmt.Sprintf("testcase #%d", i)) 76 var p *Param 77 if len(ps.ps) > 1 { 78 p = &ps.ps[1] 79 } 80 script, err := CreateFunctionInvocationScript(contract, method, p) 81 assert.Nil(t, err) 82 assert.Equal(t, ps.script, base64.StdEncoding.EncodeToString(script), fmt.Sprintf("testcase #%d", i)) 83 } 84 } 85 86 func TestInvocationScriptCreationBad(t *testing.T) { 87 contract := util.Uint160{} 88 89 var testParams = []Param{ 90 {RawMessage: []byte(`true`)}, 91 {RawMessage: []byte(`[{"type": "ByteArray", "value": "qwerty"}]`)}, 92 {RawMessage: []byte(`[{"type": "Signature", "value": "qwerty"}]`)}, 93 {RawMessage: []byte(`[{"type": "Hash160", "value": "qwerty"}]`)}, 94 {RawMessage: []byte(`[{"type": "Hash256", "value": "qwerty"}]`)}, 95 {RawMessage: []byte(`[{"type": "PublicKey", "value": 42}]`)}, 96 {RawMessage: []byte(`[{"type": "PublicKey", "value": "qwerty"}]`)}, 97 {RawMessage: []byte(`[{"type": "Integer", "value": "123q"}]`)}, 98 {RawMessage: []byte(`[{"type": "Unknown"}]`)}, 99 } 100 for i, ps := range testParams { 101 _, err := CreateFunctionInvocationScript(contract, "", &ps) 102 assert.NotNil(t, err, fmt.Sprintf("testcase #%d", i)) 103 } 104 } 105 106 func TestExpandArrayIntoScript(t *testing.T) { 107 bi := new(big.Int).Lsh(big.NewInt(1), 254) 108 rawInt := make([]byte, 32) 109 rawInt[31] = 0x40 110 111 testCases := []struct { 112 Input []Param 113 Expected []byte 114 }{ 115 { 116 Input: []Param{{RawMessage: []byte(`{"type": "String", "value": "a"}`)}}, 117 Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a')}, 118 }, 119 { 120 Input: []Param{{RawMessage: []byte(`{"type": "Array", "value": [{"type": "String", "value": "a"}]}`)}}, 121 Expected: []byte{byte(opcode.PUSHDATA1), 1, byte('a'), byte(opcode.PUSH1), byte(opcode.PACK)}, 122 }, 123 { 124 Input: []Param{{RawMessage: []byte(`{"type": "Integer", "value": "` + bi.String() + `"}`)}}, 125 Expected: append([]byte{byte(opcode.PUSHINT256)}, rawInt...), 126 }, 127 { 128 Input: []Param{{RawMessage: []byte(`{"type": "Map", "value": [{"key": {"type": "String", "value": "a" }, "value": {"type": "Integer", "value": 1}}, {"key": {"type": "String", "value": "b"}, "value": {"type": "Integer", "value": 2}}]}`)}}, 129 Expected: []byte{ 130 byte(opcode.PUSH2), // value of element #2 131 byte(opcode.PUSHDATA1), 1, byte('b'), // key of element #2 132 byte(opcode.PUSH1), // value of element #1 133 byte(opcode.PUSHDATA1), 1, byte('a'), // key of element #1 134 byte(opcode.PUSH2), // map len 135 byte(opcode.PACKMAP), 136 }, 137 }, 138 } 139 for _, c := range testCases { 140 script := io.NewBufBinWriter() 141 err := ExpandArrayIntoScript(script.BinWriter, c.Input) 142 require.NoError(t, err) 143 require.Equal(t, c.Expected, script.Bytes()) 144 } 145 errorCases := [][]Param{ 146 { 147 {RawMessage: []byte(`{"type": "Array", "value": "a"}`)}, 148 }, 149 { 150 {RawMessage: []byte(`{"type": "Array", "value": null}`)}, 151 }, 152 { 153 {RawMessage: []byte(`{"type": "Integer", "value": "` + 154 new(big.Int).Lsh(big.NewInt(1), 255).String() + `"}`)}, 155 }, 156 { 157 {RawMessage: []byte(`{"type": "Map", "value": [{"key": {"type": "InvalidT", "value": "a" }, "value": {"type": "Integer", "value": 1}}]}`)}, 158 }, 159 { 160 {RawMessage: []byte(`{"type": "Map", "value": [{"key": {"type": "String", "value": "a" }, "value": {"type": "Integer", "value": "not-an-int"}}]}`)}, 161 }, 162 } 163 for _, c := range errorCases { 164 script := io.NewBufBinWriter() 165 err := ExpandArrayIntoScript(script.BinWriter, c) 166 require.Error(t, err) 167 } 168 }