neo-go/pkg/smartcontract/nef/nef_test.go
Anna Shaleva 90705e37e9 compiler: perform NEF size check on serialization
Retun an error if the serialized NEF size exceeds stackitem.MaxSize.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-11-20 15:14:05 +03:00

192 lines
5.1 KiB
Go

package nef
import (
"encoding/base64"
"encoding/json"
"strconv"
"testing"
"github.com/nspcc-dev/neo-go/internal/random"
"github.com/nspcc-dev/neo-go/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/stretchr/testify/require"
)
func TestEncodeDecodeBinary(t *testing.T) {
script := []byte{12, 32, 84, 35, 14}
expected := &File{
Header: Header{
Magic: Magic,
Compiler: "best compiler version 1",
},
Tokens: []MethodToken{{
Hash: random.Uint160(),
Method: "method",
ParamCount: 3,
HasReturn: true,
CallFlag: callflag.WriteStates,
}},
Script: script,
}
t.Run("invalid Magic", func(t *testing.T) {
expected.Header.Magic = 123
checkDecodeError(t, expected)
})
t.Run("invalid checksum", func(t *testing.T) {
expected.Header.Magic = Magic
expected.Checksum = 123
checkDecodeError(t, expected)
})
t.Run("zero-length script", func(t *testing.T) {
expected.Script = make([]byte, 0)
expected.Checksum = expected.CalculateChecksum()
checkDecodeError(t, expected)
})
t.Run("invalid script length", func(t *testing.T) {
newScript := make([]byte, stackitem.MaxSize+1)
expected.Script = newScript
expected.Checksum = expected.CalculateChecksum()
checkDecodeError(t, expected)
})
t.Run("invalid tokens list", func(t *testing.T) {
expected.Script = script
expected.Tokens[0].Method = "_reserved"
expected.Checksum = expected.CalculateChecksum()
checkDecodeError(t, expected)
})
t.Run("positive", func(t *testing.T) {
expected.Script = script
expected.Tokens[0].Method = "method"
expected.Checksum = expected.CalculateChecksum()
expected.Header.Magic = Magic
testserdes.EncodeDecodeBinary(t, expected, &File{})
})
t.Run("positive with empty tokens", func(t *testing.T) {
expected.Script = script
// Check `Tokens` won't be deserialized to `nil`. We expect them to be non-nil slice in the related code.
expected.Tokens = []MethodToken{}
expected.Checksum = expected.CalculateChecksum()
expected.Header.Magic = Magic
testserdes.EncodeDecodeBinary(t, expected, &File{})
})
t.Run("invalid reserved bytes", func(t *testing.T) {
expected.Script = script
expected.Tokens = expected.Tokens[:0]
expected.Checksum = expected.CalculateChecksum()
bytes, err := testserdes.EncodeBinary(expected)
require.NoError(t, err)
sz := io.GetVarSize(&expected.Header)
bytes[sz] = 1
err = testserdes.DecodeBinary(bytes, new(File))
require.ErrorIs(t, err, errInvalidReserved)
bytes[sz] = 0
bytes[sz+3] = 1
err = testserdes.DecodeBinary(bytes, new(File))
require.ErrorIs(t, err, errInvalidReserved)
})
}
func checkDecodeError(t *testing.T, expected *File) {
bytes, err := testserdes.EncodeBinary(expected)
require.NoError(t, err)
require.Error(t, testserdes.DecodeBinary(bytes, &File{}))
}
func TestBytesFromBytes(t *testing.T) {
script := []byte{12, 32, 84, 35, 14}
expected := File{
Header: Header{
Magic: Magic,
Compiler: "best compiler version 1",
},
Tokens: []MethodToken{{
Hash: random.Uint160(),
Method: "someMethod",
ParamCount: 3,
HasReturn: true,
CallFlag: callflag.WriteStates,
}},
Script: script,
}
expected.Checksum = expected.CalculateChecksum()
bytes, err := expected.Bytes()
require.NoError(t, err)
actual, err := FileFromBytes(bytes)
require.NoError(t, err)
require.Equal(t, expected, actual)
}
func TestNewFileFromBytesLimits(t *testing.T) {
expected := File{
Header: Header{
Magic: Magic,
Compiler: "best compiler version 1",
},
Tokens: []MethodToken{{
Hash: random.Uint160(),
Method: "someMethod",
ParamCount: 3,
HasReturn: true,
CallFlag: callflag.WriteStates,
}},
Script: make([]byte, stackitem.MaxSize-100),
}
expected.Checksum = expected.CalculateChecksum()
bytes, err := expected.BytesLong()
require.NoError(t, err)
_, err = FileFromBytes(bytes)
require.Error(t, err)
require.Contains(t, err.Error(), "invalid NEF file size")
}
func TestMarshalUnmarshalJSON(t *testing.T) {
expected := &File{
Header: Header{
Magic: Magic,
Compiler: "test.compiler-test.ver",
},
Tokens: []MethodToken{{
Hash: util.Uint160{0x12, 0x34, 0x56, 0x78, 0x91, 0x00},
Method: "someMethod",
ParamCount: 3,
HasReturn: true,
CallFlag: callflag.WriteStates,
}},
Script: []byte{1, 2, 3, 4},
}
expected.Checksum = expected.CalculateChecksum()
data, err := json.Marshal(expected)
require.NoError(t, err)
require.JSONEq(t, `{
"magic":`+strconv.FormatUint(uint64(Magic), 10)+`,
"compiler": "test.compiler-test.ver",
"source": "",
"tokens": [
{
"hash": "0x`+expected.Tokens[0].Hash.StringLE()+`",
"method": "someMethod",
"paramcount": 3,
"hasreturnvalue": true,
"callflags": "`+expected.Tokens[0].CallFlag.String()+`"
}
],
"script": "`+base64.StdEncoding.EncodeToString(expected.Script)+`",
"checksum":`+strconv.FormatUint(uint64(expected.Checksum), 10)+`}`, string(data))
actual := new(File)
require.NoError(t, json.Unmarshal(data, actual))
require.Equal(t, expected, actual)
}