diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 3ddcb1ecc..d91cdf759 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -616,8 +616,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { case n.Op == token.NEQ: // VM has separate opcodes for number and string equality if isStringType(c.typeInfo.Types[n.X].Type) { - emit.Opcode(c.prog.BinWriter, opcode.EQUAL) - emit.Opcode(c.prog.BinWriter, opcode.NOT) + emit.Opcode(c.prog.BinWriter, opcode.NOTEQUAL) } else { emit.Opcode(c.prog.BinWriter, opcode.NUMNOTEQUAL) } diff --git a/pkg/vm/opcode/opcode.go b/pkg/vm/opcode/opcode.go index cb453c7b0..071317cdf 100644 --- a/pkg/vm/opcode/opcode.go +++ b/pkg/vm/opcode/opcode.go @@ -98,11 +98,12 @@ const ( RIGHT Opcode = 0x81 // Bitwise logic - INVERT Opcode = 0x90 - AND Opcode = 0x91 - OR Opcode = 0x92 - XOR Opcode = 0x93 - EQUAL Opcode = 0x97 + INVERT Opcode = 0x90 + AND Opcode = 0x91 + OR Opcode = 0x92 + XOR Opcode = 0x93 + EQUAL Opcode = 0x97 + NOTEQUAL Opcode = 0x98 // Arithmetic SIGN Opcode = 0x99 diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index 721dd3247..b11bfb876 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -748,7 +748,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro a := v.estack.Pop().BigInt() v.estack.PushVal(new(big.Int).Xor(b, a)) - case opcode.EQUAL: + case opcode.EQUAL, opcode.NOTEQUAL: b := v.estack.Pop() if b == nil { panic("no top-level element found") @@ -757,7 +757,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro if a == nil { panic("no second-to-the-top element found") } - v.estack.PushVal(a.value.Equals(b.value)) + v.estack.PushVal(a.value.Equals(b.value) == (op == opcode.EQUAL)) // Numeric operations. case opcode.SIGN: diff --git a/pkg/vm/vm_test.go b/pkg/vm/vm_test.go index a5922cdfa..ff50a24d2 100644 --- a/pkg/vm/vm_test.go +++ b/pkg/vm/vm_test.go @@ -1319,6 +1319,24 @@ func TestEQUALMapFalse(t *testing.T) { assert.Equal(t, &BoolItem{false}, vm.estack.Pop().value) } +func getTestFuncForVM(prog []byte, result interface{}, args ...interface{}) func(t *testing.T) { + return func(t *testing.T) { + v := load(prog) + for i := range args { + v.estack.PushVal(args[i]) + } + runVM(t, v) + require.Equal(t, 1, v.estack.Len()) + require.Equal(t, makeStackItem(result), v.estack.Pop().value) + } +} + +func TestNOTEQUALByteArray(t *testing.T) { + prog := makeProgram(opcode.NOTEQUAL) + t.Run("True", getTestFuncForVM(prog, true, []byte{1, 2}, []byte{0, 1, 2})) + t.Run("False", getTestFuncForVM(prog, false, []byte{1, 2}, []byte{1, 2})) +} + func TestNumEqual(t *testing.T) { prog := makeProgram(opcode.NUMEQUAL) vm := load(prog)