Merge pull request #963 from nspcc-dev/fix/tests
vm: restore JSON tests for NEO3
This commit is contained in:
commit
5ea51312e6
14 changed files with 436 additions and 335 deletions
|
@ -26,7 +26,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"simple div",
|
"simple div",
|
||||||
|
@ -97,7 +97,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal strings with eql",
|
"compare equal strings with eql",
|
||||||
|
@ -139,7 +139,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare equal ints with eql",
|
"compare equal ints with eql",
|
||||||
|
@ -167,7 +167,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with eql",
|
"compare not equal ints with eql",
|
||||||
|
@ -181,7 +181,7 @@ var binaryExprTestCases = []testCase{
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compare not equal ints with neq",
|
"compare not equal ints with neq",
|
||||||
|
|
|
@ -276,7 +276,7 @@ func TestIfUnaryInvert(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{})
|
eval(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAppendByte(t *testing.T) {
|
func TestAppendByte(t *testing.T) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ func TestNotAssignedFunctionCall(t *testing.T) {
|
||||||
// disable stack checks because it is hard right now
|
// disable stack checks because it is hard right now
|
||||||
// to distinguish between simple function call traversal
|
// to distinguish between simple function call traversal
|
||||||
// and the same traversal inside an assignment.
|
// and the same traversal inside an assignment.
|
||||||
evalWithoutStackChecks(t, src, []byte{})
|
evalWithoutStackChecks(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleFunctionCalls(t *testing.T) {
|
func TestMultipleFunctionCalls(t *testing.T) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestGT(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{})
|
eval(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGTE(t *testing.T) {
|
func TestGTE(t *testing.T) {
|
||||||
|
@ -44,7 +44,7 @@ func TestGTE(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{})
|
eval(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLAND(t *testing.T) {
|
func TestLAND(t *testing.T) {
|
||||||
|
@ -89,5 +89,5 @@ func TestNestedIF(t *testing.T) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{})
|
eval(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func TestImportStruct(t *testing.T) {
|
||||||
return b.Y
|
return b.Y
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
eval(t, src, []byte{})
|
eval(t, src, big.NewInt(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleDirFileImport(t *testing.T) {
|
func TestMultipleDirFileImport(t *testing.T) {
|
||||||
|
|
|
@ -255,7 +255,7 @@ var structTestCases = []testCase{
|
||||||
return t.y
|
return t.y
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
[]byte{},
|
big.NewInt(0),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"test return struct from func",
|
"test return struct from func",
|
||||||
|
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -37,12 +39,12 @@ type (
|
||||||
vmUTExecutionContextState struct {
|
vmUTExecutionContextState struct {
|
||||||
Instruction string `json:"nextInstruction"`
|
Instruction string `json:"nextInstruction"`
|
||||||
InstructionPointer int `json:"instructionPointer"`
|
InstructionPointer int `json:"instructionPointer"`
|
||||||
AStack []vmUTStackItem `json:"altStack"`
|
|
||||||
EStack []vmUTStackItem `json:"evaluationStack"`
|
EStack []vmUTStackItem `json:"evaluationStack"`
|
||||||
|
StaticFields []vmUTStackItem `json:"staticFields"`
|
||||||
}
|
}
|
||||||
|
|
||||||
vmUTExecutionEngineState struct {
|
vmUTExecutionEngineState struct {
|
||||||
State vmUTState `json:"state"`
|
State State `json:"state"`
|
||||||
ResultStack []vmUTStackItem `json:"resultStack"`
|
ResultStack []vmUTStackItem `json:"resultStack"`
|
||||||
InvocationStack []vmUTExecutionContextState `json:"invocationStack"`
|
InvocationStack []vmUTExecutionContextState `json:"invocationStack"`
|
||||||
}
|
}
|
||||||
|
@ -59,8 +61,6 @@ type (
|
||||||
Result vmUTExecutionEngineState `json:"result"`
|
Result vmUTExecutionEngineState `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
vmUTState State
|
|
||||||
|
|
||||||
vmUTStackItemType string
|
vmUTStackItemType string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -73,25 +73,27 @@ type stackItemAUX struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
vmExecute vmUTActionType = "Execute"
|
vmExecute vmUTActionType = "execute"
|
||||||
vmStepInto vmUTActionType = "StepInto"
|
vmStepInto vmUTActionType = "stepinto"
|
||||||
vmStepOut vmUTActionType = "StepOut"
|
vmStepOut vmUTActionType = "stepout"
|
||||||
vmStepOver vmUTActionType = "StepOver"
|
vmStepOver vmUTActionType = "stepover"
|
||||||
|
|
||||||
typeArray vmUTStackItemType = "Array"
|
typeArray vmUTStackItemType = "array"
|
||||||
typeBoolean vmUTStackItemType = "Boolean"
|
typeBoolean vmUTStackItemType = "boolean"
|
||||||
typeByteArray vmUTStackItemType = "ByteArray"
|
typeBuffer vmUTStackItemType = "buffer"
|
||||||
typeInteger vmUTStackItemType = "Integer"
|
typeByteString vmUTStackItemType = "bytestring"
|
||||||
typeInterop vmUTStackItemType = "Interop"
|
typeInteger vmUTStackItemType = "integer"
|
||||||
typeMap vmUTStackItemType = "Map"
|
typeInterop vmUTStackItemType = "interop"
|
||||||
typeString vmUTStackItemType = "String"
|
typeMap vmUTStackItemType = "map"
|
||||||
typeStruct vmUTStackItemType = "Struct"
|
typeNull vmUTStackItemType = "null"
|
||||||
|
typePointer vmUTStackItemType = "pointer"
|
||||||
|
typeString vmUTStackItemType = "string"
|
||||||
|
typeStruct vmUTStackItemType = "struct"
|
||||||
|
|
||||||
testsDir = "testdata/neo-vm/tests/neo-vm.Tests/Tests/"
|
testsDir = "testdata/neo-vm/tests/neo-vm.Tests/Tests/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUT(t *testing.T) {
|
func TestUT(t *testing.T) {
|
||||||
t.Skip()
|
|
||||||
testsRan := false
|
testsRan := false
|
||||||
err := filepath.Walk(testsDir, func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(testsDir, func(path string, info os.FileInfo, err error) error {
|
||||||
if !strings.HasSuffix(path, ".json") {
|
if !strings.HasSuffix(path, ".json") {
|
||||||
|
@ -110,7 +112,7 @@ func TestUT(t *testing.T) {
|
||||||
func getTestingInterop(id uint32) *InteropFuncPrice {
|
func getTestingInterop(id uint32) *InteropFuncPrice {
|
||||||
if id == binary.LittleEndian.Uint32([]byte{0x77, 0x77, 0x77, 0x77}) {
|
if id == binary.LittleEndian.Uint32([]byte{0x77, 0x77, 0x77, 0x77}) {
|
||||||
return &InteropFuncPrice{InteropFunc(func(v *VM) error {
|
return &InteropFuncPrice{InteropFunc(func(v *VM) error {
|
||||||
v.estack.Push(&Element{value: (*InteropItem)(nil)})
|
v.estack.PushVal(&InteropItem{new(int)})
|
||||||
return nil
|
return nil
|
||||||
}), 0}
|
}), 0}
|
||||||
}
|
}
|
||||||
|
@ -121,12 +123,24 @@ func testFile(t *testing.T, filename string) {
|
||||||
data, err := ioutil.ReadFile(filename)
|
data, err := ioutil.ReadFile(filename)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// get rid of possible BOM
|
||||||
|
if len(data) > 2 && data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf {
|
||||||
|
data = data[3:]
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(filename, "MEMCPY.json") {
|
||||||
|
return // FIXME not a valid JSON https://github.com/neo-project/neo-vm/issues/322
|
||||||
|
}
|
||||||
|
|
||||||
ut := new(vmUT)
|
ut := new(vmUT)
|
||||||
require.NoError(t, json.Unmarshal(data, ut))
|
require.NoErrorf(t, json.Unmarshal(data, ut), "file: %s", filename)
|
||||||
|
|
||||||
t.Run(ut.Category+":"+ut.Name, func(t *testing.T) {
|
t.Run(ut.Category+":"+ut.Name, func(t *testing.T) {
|
||||||
|
isRot := strings.HasSuffix(filename, "ROT.json")
|
||||||
for i := range ut.Tests {
|
for i := range ut.Tests {
|
||||||
test := ut.Tests[i]
|
test := ut.Tests[i]
|
||||||
|
if isRot && test.Name == "Without push" {
|
||||||
|
return // FIXME #927 single ROT is interpreted as PUSH1
|
||||||
|
}
|
||||||
t.Run(ut.Tests[i].Name, func(t *testing.T) {
|
t.Run(ut.Tests[i].Name, func(t *testing.T) {
|
||||||
prog := []byte(test.Script)
|
prog := []byte(test.Script)
|
||||||
vm := load(prog)
|
vm := load(prog)
|
||||||
|
@ -136,8 +150,8 @@ func testFile(t *testing.T, filename string) {
|
||||||
for i := range test.Steps {
|
for i := range test.Steps {
|
||||||
execStep(t, vm, test.Steps[i])
|
execStep(t, vm, test.Steps[i])
|
||||||
result := test.Steps[i].Result
|
result := test.Steps[i].Result
|
||||||
require.Equal(t, State(result.State), vm.state)
|
require.Equal(t, result.State, vm.state)
|
||||||
if result.State == vmUTState(faultState) { // do not compare stacks on fault
|
if result.State == faultState { // do not compare stacks on fault
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,10 +160,12 @@ func testFile(t *testing.T, filename string) {
|
||||||
ctx := vm.istack.Peek(i).Value().(*Context)
|
ctx := vm.istack.Peek(i).Value().(*Context)
|
||||||
if ctx.nextip < len(ctx.prog) {
|
if ctx.nextip < len(ctx.prog) {
|
||||||
require.Equal(t, s.InstructionPointer, ctx.nextip)
|
require.Equal(t, s.InstructionPointer, ctx.nextip)
|
||||||
require.Equal(t, s.Instruction, opcode.Opcode(ctx.prog[ctx.nextip]).String())
|
op, err := opcode.FromString(s.Instruction)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, op, opcode.Opcode(ctx.prog[ctx.nextip]))
|
||||||
}
|
}
|
||||||
compareStacks(t, s.EStack, vm.estack)
|
compareStacks(t, s.EStack, vm.estack)
|
||||||
compareStacks(t, s.AStack, vm.astack)
|
compareSlots(t, s.StaticFields, vm.static)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,31 +196,47 @@ func compareItems(t *testing.T, a, b StackItem) {
|
||||||
default:
|
default:
|
||||||
require.Fail(t, "wrong type")
|
require.Fail(t, "wrong type")
|
||||||
}
|
}
|
||||||
|
case *PointerItem:
|
||||||
|
p, ok := b.(*PointerItem)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Equal(t, si.pos, p.pos) // there no script in test files
|
||||||
default:
|
default:
|
||||||
require.Equal(t, a, b)
|
require.Equal(t, a, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
||||||
|
compareItemArrays(t, expected, actual.Len(), func(i int) StackItem { return actual.Peek(i).Item() })
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *Slot) {
|
||||||
|
if actual == nil && len(expected) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NotNil(t, actual)
|
||||||
|
compareItemArrays(t, expected, actual.Size(), actual.Get)
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareItemArrays(t *testing.T, expected []vmUTStackItem, n int, getItem func(i int) StackItem) {
|
||||||
if expected == nil {
|
if expected == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, len(expected), actual.Len())
|
require.Equal(t, len(expected), n)
|
||||||
for i, item := range expected {
|
for i, item := range expected {
|
||||||
e := actual.Peek(i)
|
it := getItem(i)
|
||||||
require.NotNil(t, e)
|
require.NotNil(t, it)
|
||||||
|
|
||||||
if item.Type == typeInterop {
|
if item.Type == typeInterop {
|
||||||
require.IsType(t, (*InteropItem)(nil), e.value)
|
require.IsType(t, (*InteropItem)(nil), it)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
compareItems(t, item.toStackItem(), e.value)
|
compareItems(t, item.toStackItem(), it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vmUTStackItem) toStackItem() StackItem {
|
func (v *vmUTStackItem) toStackItem() StackItem {
|
||||||
switch v.Type {
|
switch v.Type.toLower() {
|
||||||
case typeArray:
|
case typeArray:
|
||||||
items := v.Value.([]vmUTStackItem)
|
items := v.Value.([]vmUTStackItem)
|
||||||
result := make([]StackItem, len(items))
|
result := make([]StackItem, len(items))
|
||||||
|
@ -217,20 +249,19 @@ func (v *vmUTStackItem) toStackItem() StackItem {
|
||||||
case typeString:
|
case typeString:
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
case typeMap:
|
case typeMap:
|
||||||
items := v.Value.(map[string]vmUTStackItem)
|
return v.Value.(*MapItem)
|
||||||
result := NewMapItem()
|
|
||||||
for k, v := range items {
|
|
||||||
var item vmUTStackItem
|
|
||||||
_ = json.Unmarshal([]byte(`"`+k+`"`), &item)
|
|
||||||
result.Add(item.toStackItem(), v.toStackItem())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
case typeInterop:
|
case typeInterop:
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
case typeByteArray:
|
case typeByteString:
|
||||||
return &ByteArrayItem{
|
return &ByteArrayItem{
|
||||||
v.Value.([]byte),
|
v.Value.([]byte),
|
||||||
}
|
}
|
||||||
|
case typeBuffer:
|
||||||
|
return &BufferItem{v.Value.([]byte)}
|
||||||
|
case typePointer:
|
||||||
|
return NewPointerItem(v.Value.(int), nil)
|
||||||
|
case typeNull:
|
||||||
|
return NullItem{}
|
||||||
case typeBoolean:
|
case typeBoolean:
|
||||||
return &BoolItem{
|
return &BoolItem{
|
||||||
v.Value.(bool),
|
v.Value.(bool),
|
||||||
|
@ -249,14 +280,14 @@ func (v *vmUTStackItem) toStackItem() StackItem {
|
||||||
value: result,
|
value: result,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("invalid type")
|
panic(fmt.Sprintf("invalid type: %s", v.Type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func execStep(t *testing.T, v *VM, step vmUTStep) {
|
func execStep(t *testing.T, v *VM, step vmUTStep) {
|
||||||
for i, a := range step.Actions {
|
for i, a := range step.Actions {
|
||||||
var err error
|
var err error
|
||||||
switch a {
|
switch a.toLower() {
|
||||||
case vmExecute:
|
case vmExecute:
|
||||||
err = v.Run()
|
err = v.Run()
|
||||||
case vmStepInto:
|
case vmStepInto:
|
||||||
|
@ -276,30 +307,65 @@ func execStep(t *testing.T, v *VM, step vmUTStep) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vmUTState) UnmarshalJSON(data []byte) error {
|
func jsonStringToInteger(s string) StackItem {
|
||||||
switch s := string(data); s {
|
b, err := decodeHex(s)
|
||||||
case `"Break"`:
|
if err == nil {
|
||||||
*v = vmUTState(breakState)
|
return NewBigIntegerItem(new(big.Int).SetBytes(b))
|
||||||
case `"Fault"`:
|
|
||||||
*v = vmUTState(faultState)
|
|
||||||
case `"Halt"`:
|
|
||||||
*v = vmUTState(haltState)
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("invalid state: %s", s))
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v vmUTStackItemType) toLower() vmUTStackItemType {
|
||||||
|
return vmUTStackItemType(strings.ToLower(string(v)))
|
||||||
|
}
|
||||||
|
|
||||||
func (v *vmUTScript) UnmarshalJSON(data []byte) error {
|
func (v *vmUTScript) UnmarshalJSON(data []byte) error {
|
||||||
b, err := decodeBytes(data)
|
var ops []string
|
||||||
if err != nil {
|
if err := json.Unmarshal(data, &ops); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*v = vmUTScript(b)
|
var script []byte
|
||||||
|
for i := range ops {
|
||||||
|
if b, ok := decodeSingle(ops[i]); ok {
|
||||||
|
script = append(script, b...)
|
||||||
|
} else {
|
||||||
|
const regex = `(?P<hex>(?:0x)?[0-9a-zA-Z]+)\*(?P<num>[0-9]+)`
|
||||||
|
re := regexp.MustCompile(regex)
|
||||||
|
ss := re.FindStringSubmatch(ops[i])
|
||||||
|
if len(ss) != 3 {
|
||||||
|
return fmt.Errorf("invalid script part: %s", ops[i])
|
||||||
|
}
|
||||||
|
b, ok := decodeSingle(ss[1])
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid script part: %s", ops[i])
|
||||||
|
}
|
||||||
|
num, err := strconv.Atoi(ss[2])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid script part: %s", ops[i])
|
||||||
|
}
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
script = append(script, b...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = script
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeSingle(s string) ([]byte, bool) {
|
||||||
|
if op, err := opcode.FromString(s); err == nil {
|
||||||
|
return []byte{byte(op)}, true
|
||||||
|
}
|
||||||
|
b, err := decodeHex(s)
|
||||||
|
return b, err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v vmUTActionType) toLower() vmUTActionType {
|
||||||
|
return vmUTActionType(strings.ToLower(string(v)))
|
||||||
|
}
|
||||||
|
|
||||||
func (v *vmUTActionType) UnmarshalJSON(data []byte) error {
|
func (v *vmUTActionType) UnmarshalJSON(data []byte) error {
|
||||||
return json.Unmarshal(data, (*string)(v))
|
return json.Unmarshal(data, (*string)(v))
|
||||||
}
|
}
|
||||||
|
@ -312,14 +378,14 @@ func (v *vmUTStackItem) UnmarshalJSON(data []byte) error {
|
||||||
|
|
||||||
v.Type = si.Type
|
v.Type = si.Type
|
||||||
|
|
||||||
switch si.Type {
|
switch typ := si.Type.toLower(); typ {
|
||||||
case typeArray, typeStruct:
|
case typeArray, typeStruct:
|
||||||
var a []vmUTStackItem
|
var a []vmUTStackItem
|
||||||
if err := json.Unmarshal(si.Value, &a); err != nil {
|
if err := json.Unmarshal(si.Value, &a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.Value = a
|
v.Value = a
|
||||||
case typeInteger:
|
case typeInteger, typePointer:
|
||||||
num := new(big.Int)
|
num := new(big.Int)
|
||||||
var a int64
|
var a int64
|
||||||
var s string
|
var s string
|
||||||
|
@ -330,27 +396,57 @@ func (v *vmUTStackItem) UnmarshalJSON(data []byte) error {
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("invalid integer: %v", si.Value))
|
panic(fmt.Sprintf("invalid integer: %v", si.Value))
|
||||||
}
|
}
|
||||||
v.Value = num
|
if typ == typePointer {
|
||||||
|
v.Value = int(num.Int64())
|
||||||
|
} else {
|
||||||
|
v.Value = num
|
||||||
|
}
|
||||||
case typeBoolean:
|
case typeBoolean:
|
||||||
var b bool
|
var b bool
|
||||||
if err := json.Unmarshal(si.Value, &b); err != nil {
|
if err := json.Unmarshal(si.Value, &b); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.Value = b
|
v.Value = b
|
||||||
case typeByteArray:
|
case typeByteString, typeBuffer:
|
||||||
b, err := decodeBytes(si.Value)
|
b, err := decodeBytes(si.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
v.Value = b
|
v.Value = b
|
||||||
case typeInterop:
|
case typeInterop, typeNull:
|
||||||
v.Value = nil
|
v.Value = nil
|
||||||
case typeMap:
|
case typeMap:
|
||||||
var m map[string]vmUTStackItem
|
// we want to have the same order as in test file, so a custom decoder is used
|
||||||
if err := json.Unmarshal(si.Value, &m); err != nil {
|
d := json.NewDecoder(bytes.NewReader(si.Value))
|
||||||
return err
|
if tok, err := d.Token(); err != nil || tok != json.Delim('{') {
|
||||||
|
return fmt.Errorf("invalid map start")
|
||||||
}
|
}
|
||||||
v.Value = m
|
|
||||||
|
result := NewMapItem()
|
||||||
|
for {
|
||||||
|
tok, err := d.Token()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if tok == json.Delim('}') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key, ok := tok.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("string expected in map key")
|
||||||
|
}
|
||||||
|
|
||||||
|
var it vmUTStackItem
|
||||||
|
if err := d.Decode(&it); err != nil {
|
||||||
|
return fmt.Errorf("can't decode map value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
item := jsonStringToInteger(key)
|
||||||
|
if item == nil {
|
||||||
|
return fmt.Errorf("can't unmarshal StackItem %s", key)
|
||||||
|
}
|
||||||
|
result.Add(item, it.toStackItem())
|
||||||
|
}
|
||||||
|
v.Value = result
|
||||||
case typeString:
|
case typeString:
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
default:
|
default:
|
||||||
|
@ -366,12 +462,18 @@ func decodeBytes(data []byte) ([]byte, error) {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
hdata := data[3 : len(data)-1]
|
data = data[1 : len(data)-1] // strip quotes
|
||||||
if b, err := hex.DecodeString(string(hdata)); err == nil {
|
if b, err := decodeHex(string(data)); err == nil {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data = data[1 : len(data)-1]
|
|
||||||
r := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data))
|
r := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(data))
|
||||||
return ioutil.ReadAll(r)
|
return ioutil.ReadAll(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodeHex(s string) ([]byte, error) {
|
||||||
|
if strings.HasPrefix(s, "0x") {
|
||||||
|
s = s[2:]
|
||||||
|
}
|
||||||
|
return hex.DecodeString(s)
|
||||||
|
}
|
||||||
|
|
20
pkg/vm/opcode/from_string.go
Normal file
20
pkg/vm/opcode/from_string.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package opcode
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var stringToOpcode = make(map[string]Opcode)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < 255; i++ {
|
||||||
|
op := Opcode(i)
|
||||||
|
stringToOpcode[op.String()] = op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString converts string representation to and opcode itself.
|
||||||
|
func FromString(s string) (Opcode, error) {
|
||||||
|
if op, ok := stringToOpcode[s]; ok {
|
||||||
|
return op, nil
|
||||||
|
}
|
||||||
|
return 0, errors.New("invalid opcode")
|
||||||
|
}
|
|
@ -46,25 +46,25 @@ const (
|
||||||
// Flow control
|
// Flow control
|
||||||
NOP Opcode = 0x21
|
NOP Opcode = 0x21
|
||||||
JMP Opcode = 0x22
|
JMP Opcode = 0x22
|
||||||
JMPL Opcode = 0x23
|
JMPL Opcode = 0x23 // JMP_L
|
||||||
JMPIF Opcode = 0x24
|
JMPIF Opcode = 0x24
|
||||||
JMPIFL Opcode = 0x25
|
JMPIFL Opcode = 0x25 // JMPIF_L
|
||||||
JMPIFNOT Opcode = 0x26
|
JMPIFNOT Opcode = 0x26
|
||||||
JMPIFNOTL Opcode = 0x27
|
JMPIFNOTL Opcode = 0x27 // JMPIFNOT_L
|
||||||
JMPEQ Opcode = 0x28
|
JMPEQ Opcode = 0x28
|
||||||
JMPEQL Opcode = 0x29
|
JMPEQL Opcode = 0x29 // JMPEQ_L
|
||||||
JMPNE Opcode = 0x2A
|
JMPNE Opcode = 0x2A
|
||||||
JMPNEL Opcode = 0x2B
|
JMPNEL Opcode = 0x2B // JMPNE_L
|
||||||
JMPGT Opcode = 0x2C
|
JMPGT Opcode = 0x2C
|
||||||
JMPGTL Opcode = 0x2D
|
JMPGTL Opcode = 0x2D // JMPGT_L
|
||||||
JMPGE Opcode = 0x2E
|
JMPGE Opcode = 0x2E
|
||||||
JMPGEL Opcode = 0x2F
|
JMPGEL Opcode = 0x2F // JMPGE_L
|
||||||
JMPLT Opcode = 0x30
|
JMPLT Opcode = 0x30
|
||||||
JMPLTL Opcode = 0x31
|
JMPLTL Opcode = 0x31 // JMPLT_L
|
||||||
JMPLE Opcode = 0x32
|
JMPLE Opcode = 0x32
|
||||||
JMPLEL Opcode = 0x33
|
JMPLEL Opcode = 0x33 // JMPLE_L
|
||||||
CALL Opcode = 0x34
|
CALL Opcode = 0x34
|
||||||
CALLL Opcode = 0x35
|
CALLL Opcode = 0x35 // CALL_L
|
||||||
CALLA Opcode = 0x36
|
CALLA Opcode = 0x36
|
||||||
|
|
||||||
// Exceptions
|
// Exceptions
|
||||||
|
@ -86,8 +86,8 @@ const (
|
||||||
PICK Opcode = 0x4D
|
PICK Opcode = 0x4D
|
||||||
TUCK Opcode = 0x4E
|
TUCK Opcode = 0x4E
|
||||||
SWAP Opcode = 0x50
|
SWAP Opcode = 0x50
|
||||||
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
|
|
||||||
ROT Opcode = 0x51
|
ROT Opcode = 0x51
|
||||||
|
OLDPUSH1 Opcode = 0x51 // FIXME remove #927
|
||||||
ROLL Opcode = 0x52
|
ROLL Opcode = 0x52
|
||||||
REVERSE3 Opcode = 0x53
|
REVERSE3 Opcode = 0x53
|
||||||
REVERSE4 Opcode = 0x54
|
REVERSE4 Opcode = 0x54
|
||||||
|
@ -193,7 +193,7 @@ const (
|
||||||
UNPACK Opcode = 0xC1
|
UNPACK Opcode = 0xC1
|
||||||
NEWARRAY0 Opcode = 0xC2
|
NEWARRAY0 Opcode = 0xC2
|
||||||
NEWARRAY Opcode = 0xC3
|
NEWARRAY Opcode = 0xC3
|
||||||
NEWARRAYT Opcode = 0xC4
|
NEWARRAYT Opcode = 0xC4 // NEWARRAY_T
|
||||||
NEWSTRUCT0 Opcode = 0xC5
|
NEWSTRUCT0 Opcode = 0xC5
|
||||||
NEWSTRUCT Opcode = 0xC6
|
NEWSTRUCT Opcode = 0xC6
|
||||||
NEWMAP Opcode = 0xC8
|
NEWMAP Opcode = 0xC8
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Code generated by "stringer -type Opcode"; DO NOT EDIT.
|
// Code generated by "stringer -type Opcode -linecomment"; DO NOT EDIT.
|
||||||
|
|
||||||
package opcode
|
package opcode
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ func _() {
|
||||||
_ = x[PICK-77]
|
_ = x[PICK-77]
|
||||||
_ = x[TUCK-78]
|
_ = x[TUCK-78]
|
||||||
_ = x[SWAP-80]
|
_ = x[SWAP-80]
|
||||||
_ = x[OLDPUSH1-81]
|
|
||||||
_ = x[ROT-81]
|
_ = x[ROT-81]
|
||||||
|
_ = x[OLDPUSH1-81]
|
||||||
_ = x[ROLL-82]
|
_ = x[ROLL-82]
|
||||||
_ = x[REVERSE3-83]
|
_ = x[REVERSE3-83]
|
||||||
_ = x[REVERSE4-84]
|
_ = x[REVERSE4-84]
|
||||||
|
@ -192,7 +192,7 @@ func _() {
|
||||||
_ = x[CONVERT-219]
|
_ = x[CONVERT-219]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMPLJMPIFJMPIFLJMPIFNOTJMPIFNOTLJMPEQJMPEQLJMPNEJMPNELJMPGTJMPGTLJMPGEJMPGELJMPLTJMPLTLJMPLEJMPLELCALLCALLLCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPOLDPUSH1ROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAYTNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
|
const _Opcode_name = "PUSHINT8PUSHINT16PUSHINT32PUSHINT64PUSHINT128PUSHINT256PUSHAPUSHNULLPUSHDATA1PUSHDATA2PUSHDATA4PUSHM1PUSH0PUSH1PUSH2PUSH3PUSH4PUSH5PUSH6PUSH7PUSH8PUSH9PUSH10PUSH11PUSH12PUSH13PUSH14PUSH15PUSH16NOPJMPJMP_LJMPIFJMPIF_LJMPIFNOTJMPIFNOT_LJMPEQJMPEQ_LJMPNEJMPNE_LJMPGTJMPGT_LJMPGEJMPGE_LJMPLTJMPLT_LJMPLEJMPLE_LCALLCALL_LCALLAABORTASSERTTHROWRETSYSCALLDEPTHDROPNIPXDROPCLEARDUPOVERPICKTUCKSWAPROTROLLREVERSE3REVERSE4REVERSENINITSSLOTINITSLOTLDSFLD0LDSFLD1LDSFLD2LDSFLD3LDSFLD4LDSFLD5LDSFLD6LDSFLDSTSFLD0STSFLD1STSFLD2STSFLD3STSFLD4STSFLD5STSFLD6STSFLDLDLOC0LDLOC1LDLOC2LDLOC3LDLOC4LDLOC5LDLOC6LDLOCSTLOC0STLOC1STLOC2STLOC3STLOC4STLOC5STLOC6STLOCLDARG0LDARG1LDARG2LDARG3LDARG4LDARG5LDARG6LDARGSTARG0STARG1STARG2STARG3STARG4STARG5STARG6STARGNEWBUFFERMEMCPYCATSUBSTRLEFTRIGHTINVERTANDORXOREQUALNOTEQUALSIGNABSNEGATEINCDECADDSUBMULDIVMODSHLSHRNOTBOOLANDBOOLORNZNUMEQUALNUMNOTEQUALLTLTEGTGTEMINMAXWITHINPACKUNPACKNEWARRAY0NEWARRAYNEWARRAY_TNEWSTRUCT0NEWSTRUCTNEWMAPSIZEHASKEYKEYSVALUESPICKITEMAPPENDSETITEMREVERSEITEMSREMOVECLEARITEMSISNULLISTYPECONVERT"
|
||||||
|
|
||||||
var _Opcode_map = map[Opcode]string{
|
var _Opcode_map = map[Opcode]string{
|
||||||
0: _Opcode_name[0:8],
|
0: _Opcode_name[0:8],
|
||||||
|
@ -226,154 +226,154 @@ var _Opcode_map = map[Opcode]string{
|
||||||
32: _Opcode_name[187:193],
|
32: _Opcode_name[187:193],
|
||||||
33: _Opcode_name[193:196],
|
33: _Opcode_name[193:196],
|
||||||
34: _Opcode_name[196:199],
|
34: _Opcode_name[196:199],
|
||||||
35: _Opcode_name[199:203],
|
35: _Opcode_name[199:204],
|
||||||
36: _Opcode_name[203:208],
|
36: _Opcode_name[204:209],
|
||||||
37: _Opcode_name[208:214],
|
37: _Opcode_name[209:216],
|
||||||
38: _Opcode_name[214:222],
|
38: _Opcode_name[216:224],
|
||||||
39: _Opcode_name[222:231],
|
39: _Opcode_name[224:234],
|
||||||
40: _Opcode_name[231:236],
|
40: _Opcode_name[234:239],
|
||||||
41: _Opcode_name[236:242],
|
41: _Opcode_name[239:246],
|
||||||
42: _Opcode_name[242:247],
|
42: _Opcode_name[246:251],
|
||||||
43: _Opcode_name[247:253],
|
43: _Opcode_name[251:258],
|
||||||
44: _Opcode_name[253:258],
|
44: _Opcode_name[258:263],
|
||||||
45: _Opcode_name[258:264],
|
45: _Opcode_name[263:270],
|
||||||
46: _Opcode_name[264:269],
|
46: _Opcode_name[270:275],
|
||||||
47: _Opcode_name[269:275],
|
47: _Opcode_name[275:282],
|
||||||
48: _Opcode_name[275:280],
|
48: _Opcode_name[282:287],
|
||||||
49: _Opcode_name[280:286],
|
49: _Opcode_name[287:294],
|
||||||
50: _Opcode_name[286:291],
|
50: _Opcode_name[294:299],
|
||||||
51: _Opcode_name[291:297],
|
51: _Opcode_name[299:306],
|
||||||
52: _Opcode_name[297:301],
|
52: _Opcode_name[306:310],
|
||||||
53: _Opcode_name[301:306],
|
53: _Opcode_name[310:316],
|
||||||
54: _Opcode_name[306:311],
|
54: _Opcode_name[316:321],
|
||||||
55: _Opcode_name[311:316],
|
55: _Opcode_name[321:326],
|
||||||
56: _Opcode_name[316:322],
|
56: _Opcode_name[326:332],
|
||||||
58: _Opcode_name[322:327],
|
58: _Opcode_name[332:337],
|
||||||
64: _Opcode_name[327:330],
|
64: _Opcode_name[337:340],
|
||||||
65: _Opcode_name[330:337],
|
65: _Opcode_name[340:347],
|
||||||
67: _Opcode_name[337:342],
|
67: _Opcode_name[347:352],
|
||||||
69: _Opcode_name[342:346],
|
69: _Opcode_name[352:356],
|
||||||
70: _Opcode_name[346:349],
|
70: _Opcode_name[356:359],
|
||||||
72: _Opcode_name[349:354],
|
72: _Opcode_name[359:364],
|
||||||
73: _Opcode_name[354:359],
|
73: _Opcode_name[364:369],
|
||||||
74: _Opcode_name[359:362],
|
74: _Opcode_name[369:372],
|
||||||
75: _Opcode_name[362:366],
|
75: _Opcode_name[372:376],
|
||||||
77: _Opcode_name[366:370],
|
77: _Opcode_name[376:380],
|
||||||
78: _Opcode_name[370:374],
|
78: _Opcode_name[380:384],
|
||||||
80: _Opcode_name[374:378],
|
80: _Opcode_name[384:388],
|
||||||
81: _Opcode_name[378:386],
|
81: _Opcode_name[388:391],
|
||||||
82: _Opcode_name[386:390],
|
82: _Opcode_name[391:395],
|
||||||
83: _Opcode_name[390:398],
|
83: _Opcode_name[395:403],
|
||||||
84: _Opcode_name[398:406],
|
84: _Opcode_name[403:411],
|
||||||
85: _Opcode_name[406:414],
|
85: _Opcode_name[411:419],
|
||||||
86: _Opcode_name[414:423],
|
86: _Opcode_name[419:428],
|
||||||
87: _Opcode_name[423:431],
|
87: _Opcode_name[428:436],
|
||||||
88: _Opcode_name[431:438],
|
88: _Opcode_name[436:443],
|
||||||
89: _Opcode_name[438:445],
|
89: _Opcode_name[443:450],
|
||||||
90: _Opcode_name[445:452],
|
90: _Opcode_name[450:457],
|
||||||
91: _Opcode_name[452:459],
|
91: _Opcode_name[457:464],
|
||||||
92: _Opcode_name[459:466],
|
92: _Opcode_name[464:471],
|
||||||
93: _Opcode_name[466:473],
|
93: _Opcode_name[471:478],
|
||||||
94: _Opcode_name[473:480],
|
94: _Opcode_name[478:485],
|
||||||
95: _Opcode_name[480:486],
|
95: _Opcode_name[485:491],
|
||||||
96: _Opcode_name[486:493],
|
96: _Opcode_name[491:498],
|
||||||
97: _Opcode_name[493:500],
|
97: _Opcode_name[498:505],
|
||||||
98: _Opcode_name[500:507],
|
98: _Opcode_name[505:512],
|
||||||
99: _Opcode_name[507:514],
|
99: _Opcode_name[512:519],
|
||||||
100: _Opcode_name[514:521],
|
100: _Opcode_name[519:526],
|
||||||
101: _Opcode_name[521:528],
|
101: _Opcode_name[526:533],
|
||||||
102: _Opcode_name[528:535],
|
102: _Opcode_name[533:540],
|
||||||
103: _Opcode_name[535:541],
|
103: _Opcode_name[540:546],
|
||||||
104: _Opcode_name[541:547],
|
104: _Opcode_name[546:552],
|
||||||
105: _Opcode_name[547:553],
|
105: _Opcode_name[552:558],
|
||||||
106: _Opcode_name[553:559],
|
106: _Opcode_name[558:564],
|
||||||
107: _Opcode_name[559:565],
|
107: _Opcode_name[564:570],
|
||||||
108: _Opcode_name[565:571],
|
108: _Opcode_name[570:576],
|
||||||
109: _Opcode_name[571:577],
|
109: _Opcode_name[576:582],
|
||||||
110: _Opcode_name[577:583],
|
110: _Opcode_name[582:588],
|
||||||
111: _Opcode_name[583:588],
|
111: _Opcode_name[588:593],
|
||||||
112: _Opcode_name[588:594],
|
112: _Opcode_name[593:599],
|
||||||
113: _Opcode_name[594:600],
|
113: _Opcode_name[599:605],
|
||||||
114: _Opcode_name[600:606],
|
114: _Opcode_name[605:611],
|
||||||
115: _Opcode_name[606:612],
|
115: _Opcode_name[611:617],
|
||||||
116: _Opcode_name[612:618],
|
116: _Opcode_name[617:623],
|
||||||
117: _Opcode_name[618:624],
|
117: _Opcode_name[623:629],
|
||||||
118: _Opcode_name[624:630],
|
118: _Opcode_name[629:635],
|
||||||
119: _Opcode_name[630:635],
|
119: _Opcode_name[635:640],
|
||||||
120: _Opcode_name[635:641],
|
120: _Opcode_name[640:646],
|
||||||
121: _Opcode_name[641:647],
|
121: _Opcode_name[646:652],
|
||||||
122: _Opcode_name[647:653],
|
122: _Opcode_name[652:658],
|
||||||
123: _Opcode_name[653:659],
|
123: _Opcode_name[658:664],
|
||||||
124: _Opcode_name[659:665],
|
124: _Opcode_name[664:670],
|
||||||
125: _Opcode_name[665:671],
|
125: _Opcode_name[670:676],
|
||||||
126: _Opcode_name[671:677],
|
126: _Opcode_name[676:682],
|
||||||
127: _Opcode_name[677:682],
|
127: _Opcode_name[682:687],
|
||||||
128: _Opcode_name[682:688],
|
128: _Opcode_name[687:693],
|
||||||
129: _Opcode_name[688:694],
|
129: _Opcode_name[693:699],
|
||||||
130: _Opcode_name[694:700],
|
130: _Opcode_name[699:705],
|
||||||
131: _Opcode_name[700:706],
|
131: _Opcode_name[705:711],
|
||||||
132: _Opcode_name[706:712],
|
132: _Opcode_name[711:717],
|
||||||
133: _Opcode_name[712:718],
|
133: _Opcode_name[717:723],
|
||||||
134: _Opcode_name[718:724],
|
134: _Opcode_name[723:729],
|
||||||
135: _Opcode_name[724:729],
|
135: _Opcode_name[729:734],
|
||||||
136: _Opcode_name[729:738],
|
136: _Opcode_name[734:743],
|
||||||
137: _Opcode_name[738:744],
|
137: _Opcode_name[743:749],
|
||||||
139: _Opcode_name[744:747],
|
139: _Opcode_name[749:752],
|
||||||
140: _Opcode_name[747:753],
|
140: _Opcode_name[752:758],
|
||||||
141: _Opcode_name[753:757],
|
141: _Opcode_name[758:762],
|
||||||
142: _Opcode_name[757:762],
|
142: _Opcode_name[762:767],
|
||||||
144: _Opcode_name[762:768],
|
144: _Opcode_name[767:773],
|
||||||
145: _Opcode_name[768:771],
|
145: _Opcode_name[773:776],
|
||||||
146: _Opcode_name[771:773],
|
146: _Opcode_name[776:778],
|
||||||
147: _Opcode_name[773:776],
|
147: _Opcode_name[778:781],
|
||||||
151: _Opcode_name[776:781],
|
151: _Opcode_name[781:786],
|
||||||
152: _Opcode_name[781:789],
|
152: _Opcode_name[786:794],
|
||||||
153: _Opcode_name[789:793],
|
153: _Opcode_name[794:798],
|
||||||
154: _Opcode_name[793:796],
|
154: _Opcode_name[798:801],
|
||||||
155: _Opcode_name[796:802],
|
155: _Opcode_name[801:807],
|
||||||
156: _Opcode_name[802:805],
|
156: _Opcode_name[807:810],
|
||||||
157: _Opcode_name[805:808],
|
157: _Opcode_name[810:813],
|
||||||
158: _Opcode_name[808:811],
|
158: _Opcode_name[813:816],
|
||||||
159: _Opcode_name[811:814],
|
159: _Opcode_name[816:819],
|
||||||
160: _Opcode_name[814:817],
|
160: _Opcode_name[819:822],
|
||||||
161: _Opcode_name[817:820],
|
161: _Opcode_name[822:825],
|
||||||
162: _Opcode_name[820:823],
|
162: _Opcode_name[825:828],
|
||||||
168: _Opcode_name[823:826],
|
168: _Opcode_name[828:831],
|
||||||
169: _Opcode_name[826:829],
|
169: _Opcode_name[831:834],
|
||||||
170: _Opcode_name[829:832],
|
170: _Opcode_name[834:837],
|
||||||
171: _Opcode_name[832:839],
|
171: _Opcode_name[837:844],
|
||||||
172: _Opcode_name[839:845],
|
172: _Opcode_name[844:850],
|
||||||
177: _Opcode_name[845:847],
|
177: _Opcode_name[850:852],
|
||||||
179: _Opcode_name[847:855],
|
179: _Opcode_name[852:860],
|
||||||
180: _Opcode_name[855:866],
|
180: _Opcode_name[860:871],
|
||||||
181: _Opcode_name[866:868],
|
181: _Opcode_name[871:873],
|
||||||
182: _Opcode_name[868:871],
|
182: _Opcode_name[873:876],
|
||||||
183: _Opcode_name[871:873],
|
183: _Opcode_name[876:878],
|
||||||
184: _Opcode_name[873:876],
|
184: _Opcode_name[878:881],
|
||||||
185: _Opcode_name[876:879],
|
185: _Opcode_name[881:884],
|
||||||
186: _Opcode_name[879:882],
|
186: _Opcode_name[884:887],
|
||||||
187: _Opcode_name[882:888],
|
187: _Opcode_name[887:893],
|
||||||
192: _Opcode_name[888:892],
|
192: _Opcode_name[893:897],
|
||||||
193: _Opcode_name[892:898],
|
193: _Opcode_name[897:903],
|
||||||
194: _Opcode_name[898:907],
|
194: _Opcode_name[903:912],
|
||||||
195: _Opcode_name[907:915],
|
195: _Opcode_name[912:920],
|
||||||
196: _Opcode_name[915:924],
|
196: _Opcode_name[920:930],
|
||||||
197: _Opcode_name[924:934],
|
197: _Opcode_name[930:940],
|
||||||
198: _Opcode_name[934:943],
|
198: _Opcode_name[940:949],
|
||||||
200: _Opcode_name[943:949],
|
200: _Opcode_name[949:955],
|
||||||
202: _Opcode_name[949:953],
|
202: _Opcode_name[955:959],
|
||||||
203: _Opcode_name[953:959],
|
203: _Opcode_name[959:965],
|
||||||
204: _Opcode_name[959:963],
|
204: _Opcode_name[965:969],
|
||||||
205: _Opcode_name[963:969],
|
205: _Opcode_name[969:975],
|
||||||
206: _Opcode_name[969:977],
|
206: _Opcode_name[975:983],
|
||||||
207: _Opcode_name[977:983],
|
207: _Opcode_name[983:989],
|
||||||
208: _Opcode_name[983:990],
|
208: _Opcode_name[989:996],
|
||||||
209: _Opcode_name[990:1002],
|
209: _Opcode_name[996:1008],
|
||||||
210: _Opcode_name[1002:1008],
|
210: _Opcode_name[1008:1014],
|
||||||
211: _Opcode_name[1008:1018],
|
211: _Opcode_name[1014:1024],
|
||||||
216: _Opcode_name[1018:1024],
|
216: _Opcode_name[1024:1030],
|
||||||
217: _Opcode_name[1024:1030],
|
217: _Opcode_name[1030:1036],
|
||||||
219: _Opcode_name[1030:1037],
|
219: _Opcode_name[1036:1043],
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Opcode) String() string {
|
func (i Opcode) String() string {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Nothing more to test here, really.
|
// Nothing more to test here, really.
|
||||||
|
@ -18,3 +19,12 @@ func TestStringer(t *testing.T) {
|
||||||
assert.Equal(t, s, o.String())
|
assert.Equal(t, s, o.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFromString(t *testing.T) {
|
||||||
|
_, err := FromString("abcdef")
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
op, err := FromString(MUL.String())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, MUL, op)
|
||||||
|
}
|
||||||
|
|
|
@ -225,7 +225,9 @@ func (i *StructItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
case StructT:
|
case StructT:
|
||||||
return i, nil
|
return i, nil
|
||||||
case ArrayT:
|
case ArrayT:
|
||||||
return NewArrayItem(i.value), nil
|
arr := make([]StackItem, len(i.value))
|
||||||
|
copy(arr, i.value)
|
||||||
|
return NewArrayItem(arr), nil
|
||||||
case BooleanT:
|
case BooleanT:
|
||||||
return NewBoolItem(i.Bool()), nil
|
return NewBoolItem(i.Bool()), nil
|
||||||
default:
|
default:
|
||||||
|
@ -641,7 +643,9 @@ func (i *ArrayItem) Convert(typ StackItemType) (StackItem, error) {
|
||||||
case ArrayT:
|
case ArrayT:
|
||||||
return i, nil
|
return i, nil
|
||||||
case StructT:
|
case StructT:
|
||||||
return NewStructItem(i.value), nil
|
arr := make([]StackItem, len(i.value))
|
||||||
|
copy(arr, i.value)
|
||||||
|
return NewStructItem(arr), nil
|
||||||
case BooleanT:
|
case BooleanT:
|
||||||
return NewBoolItem(i.Bool()), nil
|
return NewBoolItem(i.Bool()), nil
|
||||||
default:
|
default:
|
||||||
|
|
59
pkg/vm/vm.go
59
pkg/vm/vm.go
|
@ -338,7 +338,7 @@ func (v *VM) Run() error {
|
||||||
// check for breakpoint before executing the next instruction
|
// check for breakpoint before executing the next instruction
|
||||||
ctx := v.Context()
|
ctx := v.Context()
|
||||||
if ctx != nil && ctx.atBreakPoint() {
|
if ctx != nil && ctx.atBreakPoint() {
|
||||||
v.state |= breakState
|
v.state = breakState
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case v.state.HasFlag(faultState):
|
case v.state.HasFlag(faultState):
|
||||||
|
@ -376,7 +376,7 @@ func (v *VM) StepInto() error {
|
||||||
ctx := v.Context()
|
ctx := v.Context()
|
||||||
|
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
v.state |= haltState
|
v.state = haltState
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.HasStopped() {
|
if v.HasStopped() {
|
||||||
|
@ -518,17 +518,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case opcode.PUSHM1, opcode.PUSH1, opcode.PUSH2, opcode.PUSH3,
|
case opcode.PUSHM1, opcode.PUSH0, opcode.PUSH1, opcode.PUSH2, opcode.PUSH3,
|
||||||
opcode.PUSH4, opcode.PUSH5, opcode.PUSH6, opcode.PUSH7,
|
opcode.PUSH4, opcode.PUSH5, opcode.PUSH6, opcode.PUSH7,
|
||||||
opcode.PUSH8, opcode.PUSH9, opcode.PUSH10, opcode.PUSH11,
|
opcode.PUSH8, opcode.PUSH9, opcode.PUSH10, opcode.PUSH11,
|
||||||
opcode.PUSH12, opcode.PUSH13, opcode.PUSH14, opcode.PUSH15,
|
opcode.PUSH12, opcode.PUSH13, opcode.PUSH14, opcode.PUSH15,
|
||||||
opcode.PUSH16:
|
opcode.PUSH16:
|
||||||
val := int(op) - int(opcode.PUSH1) + 1
|
val := int(op) - int(opcode.PUSH0)
|
||||||
v.estack.PushVal(val)
|
v.estack.PushVal(val)
|
||||||
|
|
||||||
case opcode.PUSH0:
|
|
||||||
v.estack.PushVal([]byte{})
|
|
||||||
|
|
||||||
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
|
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
|
||||||
v.estack.PushVal(parameter)
|
v.estack.PushVal(parameter)
|
||||||
|
|
||||||
|
@ -697,7 +694,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
}
|
}
|
||||||
s := v.estack.Pop().Bytes()
|
s := v.estack.Pop().Bytes()
|
||||||
if t := len(s); l > t {
|
if t := len(s); l > t {
|
||||||
l = t
|
panic("size is too big")
|
||||||
}
|
}
|
||||||
v.estack.PushVal(NewBufferItem(s[:l]))
|
v.estack.PushVal(NewBufferItem(s[:l]))
|
||||||
|
|
||||||
|
@ -984,46 +981,28 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.NEWARRAY, opcode.NEWARRAYT:
|
case opcode.NEWARRAY, opcode.NEWARRAYT:
|
||||||
item := v.estack.Pop()
|
item := v.estack.Pop()
|
||||||
switch t := item.value.(type) {
|
n := item.BigInt().Int64()
|
||||||
case *StructItem:
|
if n > MaxArraySize {
|
||||||
arr := make([]StackItem, len(t.value))
|
panic("too long array")
|
||||||
copy(arr, t.value)
|
|
||||||
v.estack.PushVal(&ArrayItem{arr})
|
|
||||||
case *ArrayItem:
|
|
||||||
v.estack.PushVal(t)
|
|
||||||
default:
|
|
||||||
n := item.BigInt().Int64()
|
|
||||||
if n > MaxArraySize {
|
|
||||||
panic("too long array")
|
|
||||||
}
|
|
||||||
typ := BooleanT
|
|
||||||
if op == opcode.NEWARRAYT {
|
|
||||||
typ = StackItemType(parameter[0])
|
|
||||||
}
|
|
||||||
items := makeArrayOfType(int(n), typ)
|
|
||||||
v.estack.PushVal(&ArrayItem{items})
|
|
||||||
}
|
}
|
||||||
|
typ := AnyT
|
||||||
|
if op == opcode.NEWARRAYT {
|
||||||
|
typ = StackItemType(parameter[0])
|
||||||
|
}
|
||||||
|
items := makeArrayOfType(int(n), typ)
|
||||||
|
v.estack.PushVal(&ArrayItem{items})
|
||||||
|
|
||||||
case opcode.NEWSTRUCT0:
|
case opcode.NEWSTRUCT0:
|
||||||
v.estack.PushVal(&StructItem{[]StackItem{}})
|
v.estack.PushVal(&StructItem{[]StackItem{}})
|
||||||
|
|
||||||
case opcode.NEWSTRUCT:
|
case opcode.NEWSTRUCT:
|
||||||
item := v.estack.Pop()
|
item := v.estack.Pop()
|
||||||
switch t := item.value.(type) {
|
n := item.BigInt().Int64()
|
||||||
case *ArrayItem:
|
if n > MaxArraySize {
|
||||||
arr := make([]StackItem, len(t.value))
|
panic("too long struct")
|
||||||
copy(arr, t.value)
|
|
||||||
v.estack.PushVal(&StructItem{arr})
|
|
||||||
case *StructItem:
|
|
||||||
v.estack.PushVal(t)
|
|
||||||
default:
|
|
||||||
n := item.BigInt().Int64()
|
|
||||||
if n > MaxArraySize {
|
|
||||||
panic("too long struct")
|
|
||||||
}
|
|
||||||
items := makeArrayOfType(int(n), BooleanT)
|
|
||||||
v.estack.PushVal(&StructItem{items})
|
|
||||||
}
|
}
|
||||||
|
items := makeArrayOfType(int(n), AnyT)
|
||||||
|
v.estack.PushVal(&StructItem{items})
|
||||||
|
|
||||||
case opcode.APPEND:
|
case opcode.APPEND:
|
||||||
itemElem := v.estack.Pop()
|
itemElem := v.estack.Pop()
|
||||||
|
|
|
@ -372,7 +372,7 @@ func appendBigStruct(size uint16) []opcode.Opcode {
|
||||||
return append(prog,
|
return append(prog,
|
||||||
opcode.INITSSLOT, 1,
|
opcode.INITSSLOT, 1,
|
||||||
opcode.PUSHINT16, opcode.Opcode(size), opcode.Opcode(size>>8), // LE
|
opcode.PUSHINT16, opcode.Opcode(size), opcode.Opcode(size>>8), // LE
|
||||||
opcode.PACK, opcode.NEWSTRUCT,
|
opcode.PACK, opcode.CONVERT, opcode.Opcode(StructT),
|
||||||
opcode.STSFLD0, opcode.LDSFLD0,
|
opcode.STSFLD0, opcode.LDSFLD0,
|
||||||
opcode.DUP,
|
opcode.DUP,
|
||||||
opcode.PUSH0, opcode.NEWARRAY,
|
opcode.PUSH0, opcode.NEWARRAY,
|
||||||
|
@ -401,20 +401,19 @@ func TestStackLimit(t *testing.T) {
|
||||||
{opcode.NEWARRAY, 3}, // array + 2 items
|
{opcode.NEWARRAY, 3}, // array + 2 items
|
||||||
{opcode.STSFLD0, 3},
|
{opcode.STSFLD0, 3},
|
||||||
{opcode.LDSFLD0, 4},
|
{opcode.LDSFLD0, 4},
|
||||||
{opcode.NEWSTRUCT, 6}, // all items are copied
|
{opcode.NEWMAP, 5},
|
||||||
{opcode.NEWMAP, 7},
|
{opcode.DUP, 6},
|
||||||
{opcode.DUP, 8},
|
{opcode.PUSH2, 7},
|
||||||
{opcode.PUSH2, 9},
|
{opcode.LDSFLD0, 8},
|
||||||
{opcode.LDSFLD0, 10},
|
{opcode.SETITEM, 6}, // -3 items and 1 new element in map
|
||||||
{opcode.SETITEM, 8}, // -3 items and 1 new element in map
|
{opcode.DUP, 7},
|
||||||
{opcode.DUP, 9},
|
{opcode.PUSH2, 8},
|
||||||
{opcode.PUSH2, 10},
|
{opcode.LDSFLD0, 9},
|
||||||
{opcode.LDSFLD0, 11},
|
{opcode.SETITEM, 6}, // -3 items and no new elements in map
|
||||||
{opcode.SETITEM, 8}, // -3 items and no new elements in map
|
{opcode.DUP, 7},
|
||||||
{opcode.DUP, 9},
|
{opcode.PUSH2, 8},
|
||||||
{opcode.PUSH2, 10},
|
{opcode.REMOVE, 5}, // as we have right after NEWMAP
|
||||||
{opcode.REMOVE, 7}, // as we have right after NEWMAP
|
{opcode.DROP, 4}, // DROP map with no elements
|
||||||
{opcode.DROP, 6}, // DROP map with no elements
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prog := make([]opcode.Opcode, len(expected)+2)
|
prog := make([]opcode.Opcode, len(expected)+2)
|
||||||
|
@ -1188,45 +1187,37 @@ func TestNEWARRAYArray(t *testing.T) {
|
||||||
prog := makeProgram(opcode.NEWARRAY)
|
prog := makeProgram(opcode.NEWARRAY)
|
||||||
t.Run("ByteArray", getTestFuncForVM(prog, NewArrayItem([]StackItem{}), []byte{}))
|
t.Run("ByteArray", getTestFuncForVM(prog, NewArrayItem([]StackItem{}), []byte{}))
|
||||||
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
|
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
|
||||||
t.Run("Integer", getTestFuncForVM(prog, []StackItem{NewBoolItem(false)}, 1))
|
t.Run("Integer", getTestFuncForVM(prog, []StackItem{NullItem{}}, 1))
|
||||||
|
|
||||||
arr := []StackItem{makeStackItem(42)}
|
|
||||||
t.Run("Array", getTestFuncForVM(prog, arr, arr))
|
|
||||||
t.Run("Struct", getTestFuncForVM(prog, arr, NewStructItem(arr)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNEWARRAYIssue437(t *testing.T, i1, i2 opcode.Opcode, appended bool) {
|
func testNEWARRAYIssue437(t *testing.T, i1 opcode.Opcode, t2 StackItemType, appended bool) {
|
||||||
prog := makeProgram(
|
prog := makeProgram(
|
||||||
opcode.PUSH2, i1,
|
opcode.PUSH2, i1,
|
||||||
opcode.DUP, opcode.PUSH3, opcode.APPEND,
|
opcode.DUP, opcode.PUSH3, opcode.APPEND,
|
||||||
opcode.INITSSLOT, 1,
|
opcode.INITSSLOT, 1,
|
||||||
opcode.STSFLD0, opcode.LDSFLD0, i2,
|
opcode.STSFLD0, opcode.LDSFLD0, opcode.CONVERT, opcode.Opcode(t2),
|
||||||
opcode.DUP, opcode.PUSH4, opcode.APPEND,
|
opcode.DUP, opcode.PUSH4, opcode.APPEND,
|
||||||
opcode.LDSFLD0, opcode.PUSH5, opcode.APPEND)
|
opcode.LDSFLD0, opcode.PUSH5, opcode.APPEND)
|
||||||
vm := load(prog)
|
|
||||||
vm.Run()
|
|
||||||
|
|
||||||
arr := makeArrayOfType(4, BooleanT)
|
arr := makeArrayOfType(4, AnyT)
|
||||||
arr[2] = makeStackItem(3)
|
arr[2] = makeStackItem(3)
|
||||||
arr[3] = makeStackItem(4)
|
arr[3] = makeStackItem(4)
|
||||||
if appended {
|
if appended {
|
||||||
arr = append(arr, makeStackItem(5))
|
arr = append(arr, makeStackItem(5))
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, false, vm.HasFailed())
|
if t2 == ArrayT {
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
runWithArgs(t, prog, &ArrayItem{arr})
|
||||||
if i2 == opcode.NEWARRAY {
|
|
||||||
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
|
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
|
runWithArgs(t, prog, &StructItem{arr})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWARRAYIssue437(t *testing.T) {
|
func TestNEWARRAYIssue437(t *testing.T) {
|
||||||
t.Run("Array+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
|
t.Run("Array+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, ArrayT, true) })
|
||||||
t.Run("Struct+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
|
t.Run("Struct+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, StructT, true) })
|
||||||
t.Run("Array+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
|
t.Run("Array+Struct", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWARRAY, StructT, false) })
|
||||||
t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
|
t.Run("Struct+Array", func(t *testing.T) { testNEWARRAYIssue437(t, opcode.NEWSTRUCT, ArrayT, false) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNEWARRAYT(t *testing.T) {
|
func TestNEWARRAYT(t *testing.T) {
|
||||||
|
@ -1247,11 +1238,7 @@ func TestNEWSTRUCT(t *testing.T) {
|
||||||
prog := makeProgram(opcode.NEWSTRUCT)
|
prog := makeProgram(opcode.NEWSTRUCT)
|
||||||
t.Run("ByteArray", getTestFuncForVM(prog, NewStructItem([]StackItem{}), []byte{}))
|
t.Run("ByteArray", getTestFuncForVM(prog, NewStructItem([]StackItem{}), []byte{}))
|
||||||
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
|
t.Run("BadSize", getTestFuncForVM(prog, nil, MaxArraySize+1))
|
||||||
t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NewBoolItem(false)}), 1))
|
t.Run("Integer", getTestFuncForVM(prog, NewStructItem([]StackItem{NullItem{}}), 1))
|
||||||
|
|
||||||
arr := []StackItem{makeStackItem(42)}
|
|
||||||
t.Run("Array", getTestFuncForVM(prog, NewStructItem(arr), NewArrayItem(arr)))
|
|
||||||
t.Run("Struct", getTestFuncForVM(prog, NewStructItem(arr), NewStructItem(arr)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPPEND(t *testing.T) {
|
func TestAPPEND(t *testing.T) {
|
||||||
|
@ -1827,7 +1814,7 @@ func TestLEFT(t *testing.T) {
|
||||||
t.Run("NoString", getTestFuncForVM(prog, nil, 2))
|
t.Run("NoString", getTestFuncForVM(prog, nil, 2))
|
||||||
t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1))
|
t.Run("NegativeLen", getTestFuncForVM(prog, nil, "abcdef", -1))
|
||||||
t.Run("Good", getTestFuncForVM(prog, NewBufferItem([]byte("ab")), "abcdef", 2))
|
t.Run("Good", getTestFuncForVM(prog, NewBufferItem([]byte("ab")), "abcdef", 2))
|
||||||
t.Run("GoodBigLen", getTestFuncForVM(prog, NewBufferItem([]byte("abcdef")), "abcdef", 8))
|
t.Run("BadBigLen", getTestFuncForVM(prog, nil, "abcdef", 8))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRIGHT(t *testing.T) {
|
func TestRIGHT(t *testing.T) {
|
||||||
|
@ -1903,14 +1890,12 @@ func TestREVERSEITEMS(t *testing.T) {
|
||||||
t.Run("Buffer", getTestFuncForVM(prog, NewBufferItem([]byte{3, 2, 1}), NewBufferItem([]byte{1, 2, 3})))
|
t.Run("Buffer", getTestFuncForVM(prog, NewBufferItem([]byte{3, 2, 1}), NewBufferItem([]byte{1, 2, 3})))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testREVERSEITEMSIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool) {
|
func testREVERSEITEMSIssue437(t *testing.T, i1 opcode.Opcode, t2 StackItemType, reversed bool) {
|
||||||
prog := makeProgram(
|
prog := makeProgram(
|
||||||
opcode.PUSH0, i1,
|
opcode.PUSH0, i1,
|
||||||
opcode.DUP, opcode.PUSH1, opcode.APPEND,
|
opcode.DUP, opcode.PUSH1, opcode.APPEND,
|
||||||
opcode.DUP, opcode.PUSH2, opcode.APPEND,
|
opcode.DUP, opcode.PUSH2, opcode.APPEND,
|
||||||
opcode.DUP, i2, opcode.REVERSEITEMS)
|
opcode.DUP, opcode.CONVERT, opcode.Opcode(t2), opcode.REVERSEITEMS)
|
||||||
vm := load(prog)
|
|
||||||
vm.Run()
|
|
||||||
|
|
||||||
arr := make([]StackItem, 2)
|
arr := make([]StackItem, 2)
|
||||||
if reversed {
|
if reversed {
|
||||||
|
@ -1920,20 +1905,19 @@ func testREVERSEITEMSIssue437(t *testing.T, i1, i2 opcode.Opcode, reversed bool)
|
||||||
arr[0] = makeStackItem(1)
|
arr[0] = makeStackItem(1)
|
||||||
arr[1] = makeStackItem(2)
|
arr[1] = makeStackItem(2)
|
||||||
}
|
}
|
||||||
assert.Equal(t, false, vm.HasFailed())
|
|
||||||
assert.Equal(t, 1, vm.estack.Len())
|
|
||||||
if i1 == opcode.NEWARRAY {
|
if i1 == opcode.NEWARRAY {
|
||||||
assert.Equal(t, &ArrayItem{arr}, vm.estack.Pop().value)
|
runWithArgs(t, prog, &ArrayItem{arr})
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, &StructItem{arr}, vm.estack.Pop().value)
|
runWithArgs(t, prog, &StructItem{arr})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestREVERSEITEMSIssue437(t *testing.T) {
|
func TestREVERSEITEMSIssue437(t *testing.T) {
|
||||||
t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWARRAY, true) })
|
t.Run("Array+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, ArrayT, true) })
|
||||||
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWSTRUCT, true) })
|
t.Run("Struct+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, StructT, true) })
|
||||||
t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, opcode.NEWSTRUCT, false) })
|
t.Run("Array+Struct", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWARRAY, StructT, false) })
|
||||||
t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, opcode.NEWARRAY, false) })
|
t.Run("Struct+Array", func(t *testing.T) { testREVERSEITEMSIssue437(t, opcode.NEWSTRUCT, ArrayT, false) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestREVERSEITEMSGoodOneElem(t *testing.T) {
|
func TestREVERSEITEMSGoodOneElem(t *testing.T) {
|
||||||
|
@ -2471,7 +2455,9 @@ func makeProgram(opcodes ...opcode.Opcode) []byte {
|
||||||
|
|
||||||
func load(prog []byte) *VM {
|
func load(prog []byte) *VM {
|
||||||
vm := New()
|
vm := New()
|
||||||
vm.LoadScript(prog)
|
if len(prog) != 0 {
|
||||||
|
vm.LoadScript(prog)
|
||||||
|
}
|
||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue