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  }