Merge pull request #784 from nspcc-dev/neo3/null

vm: support NULL stack item
This commit is contained in:
Roman Khimov 2020-04-10 10:38:17 +03:00 committed by GitHub
commit 5a22651e36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 0 deletions

View file

@ -30,6 +30,7 @@ const (
ArrayType ParamType = 0x10
MapType ParamType = 0x12
InteropInterfaceType ParamType = 0xf0
AnyType ParamType = 0xfe
VoidType ParamType = 0xff
)
@ -60,6 +61,8 @@ func (pt ParamType) String() string {
return "InteropInterface"
case VoidType:
return "Void"
case AnyType:
return "Any"
default:
return ""
}
@ -154,6 +157,8 @@ func ParseParamType(typ string) (ParamType, error) {
return InteropInterfaceType, nil
case "void":
return VoidType, nil
case "any":
return AnyType, nil
default:
return UnknownType, errors.Errorf("Unknown contract parameter type: %s", typ)
}

View file

@ -89,6 +89,7 @@ const (
PUSHDATA2 Opcode = 0x4D
PUSHDATA4 Opcode = 0x4E
PUSHM1 Opcode = 0x4F
PUSHNULL Opcode = 0x50
PUSH1 Opcode = 0x51
PUSHT Opcode = PUSH1
PUSH2 Opcode = 0x52
@ -118,6 +119,8 @@ const (
SYSCALL Opcode = 0x68
TAILCALL Opcode = 0x69
ISNULL Opcode = 0x70
// Stack
DUPFROMALTSTACK Opcode = 0x6A
TOALTSTACK Opcode = 0x6B

View file

@ -185,6 +185,44 @@ func (i *StructItem) Clone() *StructItem {
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.
type BigIntegerItem struct {
value *big.Int

View file

@ -560,6 +560,13 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
case opcode.PUSHDATA1, opcode.PUSHDATA2, opcode.PUSHDATA4:
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.
case opcode.TOALTSTACK:
v.astack.Push(v.estack.Pop())

View file

@ -197,6 +197,31 @@ func TestStackLimitPUSH1Bad(t *testing.T) {
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:
// 1. pushes size Structs on stack
// 2. packs them into a new struct