Merge pull request #784 from nspcc-dev/neo3/null
vm: support NULL stack item
This commit is contained in:
commit
5a22651e36
5 changed files with 78 additions and 0 deletions
|
@ -30,6 +30,7 @@ const (
|
||||||
ArrayType ParamType = 0x10
|
ArrayType ParamType = 0x10
|
||||||
MapType ParamType = 0x12
|
MapType ParamType = 0x12
|
||||||
InteropInterfaceType ParamType = 0xf0
|
InteropInterfaceType ParamType = 0xf0
|
||||||
|
AnyType ParamType = 0xfe
|
||||||
VoidType ParamType = 0xff
|
VoidType ParamType = 0xff
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,6 +61,8 @@ func (pt ParamType) String() string {
|
||||||
return "InteropInterface"
|
return "InteropInterface"
|
||||||
case VoidType:
|
case VoidType:
|
||||||
return "Void"
|
return "Void"
|
||||||
|
case AnyType:
|
||||||
|
return "Any"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -154,6 +157,8 @@ func ParseParamType(typ string) (ParamType, error) {
|
||||||
return InteropInterfaceType, nil
|
return InteropInterfaceType, nil
|
||||||
case "void":
|
case "void":
|
||||||
return VoidType, nil
|
return VoidType, nil
|
||||||
|
case "any":
|
||||||
|
return AnyType, nil
|
||||||
default:
|
default:
|
||||||
return UnknownType, errors.Errorf("Unknown contract parameter type: %s", typ)
|
return UnknownType, errors.Errorf("Unknown contract parameter type: %s", typ)
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ const (
|
||||||
PUSHDATA2 Opcode = 0x4D
|
PUSHDATA2 Opcode = 0x4D
|
||||||
PUSHDATA4 Opcode = 0x4E
|
PUSHDATA4 Opcode = 0x4E
|
||||||
PUSHM1 Opcode = 0x4F
|
PUSHM1 Opcode = 0x4F
|
||||||
|
PUSHNULL Opcode = 0x50
|
||||||
PUSH1 Opcode = 0x51
|
PUSH1 Opcode = 0x51
|
||||||
PUSHT Opcode = PUSH1
|
PUSHT Opcode = PUSH1
|
||||||
PUSH2 Opcode = 0x52
|
PUSH2 Opcode = 0x52
|
||||||
|
@ -118,6 +119,8 @@ const (
|
||||||
SYSCALL Opcode = 0x68
|
SYSCALL Opcode = 0x68
|
||||||
TAILCALL Opcode = 0x69
|
TAILCALL Opcode = 0x69
|
||||||
|
|
||||||
|
ISNULL Opcode = 0x70
|
||||||
|
|
||||||
// Stack
|
// Stack
|
||||||
DUPFROMALTSTACK Opcode = 0x6A
|
DUPFROMALTSTACK Opcode = 0x6A
|
||||||
TOALTSTACK Opcode = 0x6B
|
TOALTSTACK Opcode = 0x6B
|
||||||
|
|
|
@ -185,6 +185,44 @@ func (i *StructItem) Clone() *StructItem {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NullItem represents null on the stack.
|
||||||
|
type NullItem struct{}
|
||||||
|
|
||||||
|
// String implements StackItem interface.
|
||||||
|
func (i NullItem) String() string {
|
||||||
|
return "Null"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value implements StackItem interface.
|
||||||
|
func (i NullItem) Value() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dup implements StackItem interface.
|
||||||
|
// There is no need to perform a real copy here,
|
||||||
|
// as NullItem has no internal state.
|
||||||
|
func (i NullItem) Dup() StackItem {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryBytes implements StackItem interface.
|
||||||
|
func (i NullItem) TryBytes() ([]byte, error) {
|
||||||
|
return nil, errors.New("can't convert Null to ByteArray")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals implements StackItem interface.
|
||||||
|
func (i NullItem) Equals(s StackItem) bool {
|
||||||
|
_, ok := s.(NullItem)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToContractParameter implements StackItem interface.
|
||||||
|
func (i NullItem) ToContractParameter(map[StackItem]bool) smartcontract.Parameter {
|
||||||
|
return smartcontract.Parameter{
|
||||||
|
Type: smartcontract.AnyType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BigIntegerItem represents a big integer on the stack.
|
// BigIntegerItem represents a big integer on the stack.
|
||||||
type BigIntegerItem struct {
|
type BigIntegerItem struct {
|
||||||
value *big.Int
|
value *big.Int
|
||||||
|
|
|
@ -560,6 +560,13 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
|
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
|
||||||
v.estack.PushVal(parameter)
|
v.estack.PushVal(parameter)
|
||||||
|
|
||||||
|
case opcode.PUSHNULL:
|
||||||
|
v.estack.PushVal(NullItem{})
|
||||||
|
|
||||||
|
case opcode.ISNULL:
|
||||||
|
res := v.estack.Pop().value.Equals(NullItem{})
|
||||||
|
v.estack.PushVal(res)
|
||||||
|
|
||||||
// Stack operations.
|
// Stack operations.
|
||||||
case opcode.TOALTSTACK:
|
case opcode.TOALTSTACK:
|
||||||
v.astack.Push(v.estack.Pop())
|
v.astack.Push(v.estack.Pop())
|
||||||
|
|
|
@ -197,6 +197,31 @@ func TestStackLimitPUSH1Bad(t *testing.T) {
|
||||||
checkVMFailed(t, v)
|
checkVMFailed(t, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPUSHNULL(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PUSHNULL, opcode.PUSHNULL, opcode.EQUAL)
|
||||||
|
v := load(prog)
|
||||||
|
require.NoError(t, v.Step())
|
||||||
|
require.Equal(t, 1, v.estack.Len())
|
||||||
|
runVM(t, v)
|
||||||
|
require.True(t, v.estack.Pop().Bool())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestISNULL(t *testing.T) {
|
||||||
|
t.Run("Integer", func(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PUSH1, opcode.ISNULL)
|
||||||
|
v := load(prog)
|
||||||
|
runVM(t, v)
|
||||||
|
require.False(t, v.estack.Pop().Bool())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Null", func(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PUSHNULL, opcode.ISNULL)
|
||||||
|
v := load(prog)
|
||||||
|
runVM(t, v)
|
||||||
|
require.True(t, v.estack.Pop().Bool())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// appendBigStruct returns a program which:
|
// appendBigStruct returns a program which:
|
||||||
// 1. pushes size Structs on stack
|
// 1. pushes size Structs on stack
|
||||||
// 2. packs them into a new struct
|
// 2. packs them into a new struct
|
||||||
|
|
Loading…
Reference in a new issue