vm: implement HASKEY opcode

This commit is contained in:
Evgenii Stratonikov 2019-09-24 15:25:57 +03:00
parent df18da0ac9
commit 0fb4bb05cf
2 changed files with 127 additions and 1 deletions

View file

@ -912,12 +912,33 @@ func (v *VM) execute(ctx *Context, op Instruction) {
} }
v.estack.PushVal(sigok) v.estack.PushVal(sigok)
case HASKEY, KEYS, VALUES: case KEYS, VALUES:
panic("unimplemented") panic("unimplemented")
case NEWMAP: case NEWMAP:
v.estack.Push(&Element{value: NewMapItem()}) v.estack.Push(&Element{value: NewMapItem()})
case HASKEY:
key := v.estack.Pop()
validateMapKey(key)
c := v.estack.Pop()
if c == nil {
panic("no value found")
}
switch t := c.value.(type) {
case *ArrayItem, *StructItem:
index := key.BigInt().Int64()
if index < 0 {
panic("negative index")
}
v.estack.PushVal(index < int64(len(c.Array())))
case *MapItem:
v.estack.PushVal(t.Has(key.value))
default:
panic("wrong collection type")
}
// Cryptographic operations. // Cryptographic operations.
case SHA1: case SHA1:
b := v.estack.Pop().Bytes() b := v.estack.Pop().Bytes()
@ -961,6 +982,16 @@ func makeArrayOfFalses(n int) []StackItem {
return items return items
} }
func validateMapKey(key *Element) {
if key == nil {
panic("no key found")
}
switch key.value.(type) {
case *ArrayItem, *StructItem, *MapItem:
panic("key can't be a collection")
}
}
func init() { func init() {
log.SetPrefix("NEO-GO-VM > ") log.SetPrefix("NEO-GO-VM > ")
log.SetFlags(0) log.SetFlags(0)

View file

@ -673,6 +673,101 @@ func TestSIZEBool(t *testing.T) {
assert.Equal(t, makeStackItem(1), vm.estack.Pop().value) assert.Equal(t, makeStackItem(1), vm.estack.Pop().value)
} }
func TestHASKEYArrayTrue(t *testing.T) {
prog := makeProgram(PUSH5, NEWARRAY, PUSH4, HASKEY)
vm := load(prog)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
}
func TestHASKEYArrayFalse(t *testing.T) {
prog := makeProgram(PUSH5, NEWARRAY, PUSH5, HASKEY)
vm := load(prog)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
}
func TestHASKEYStructTrue(t *testing.T) {
prog := makeProgram(PUSH5, NEWSTRUCT, PUSH4, HASKEY)
vm := load(prog)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
}
func TestHASKEYStructFalse(t *testing.T) {
prog := makeProgram(PUSH5, NEWSTRUCT, PUSH5, HASKEY)
vm := load(prog)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
}
func TestHASKEYMapTrue(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
m := NewMapItem()
m.Add(makeStackItem(5), makeStackItem(6))
vm.estack.Push(&Element{value: m})
vm.estack.PushVal(5)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(true), vm.estack.Pop().value)
}
func TestHASKEYMapFalse(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
m := NewMapItem()
m.Add(makeStackItem(5), makeStackItem(6))
vm.estack.Push(&Element{value: m})
vm.estack.PushVal(6)
vm.Run()
assert.Equal(t, false, vm.HasFailed())
assert.Equal(t, 1, vm.estack.Len())
assert.Equal(t, makeStackItem(false), vm.estack.Pop().value)
}
func TestHASKEYNoArguments(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestHASKEY1Argument(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
vm.estack.PushVal(1)
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestHASKEYWrongKeyType(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
vm.estack.PushVal([]StackItem{})
vm.estack.PushVal([]StackItem{})
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestHASKEYWrongCollectionType(t *testing.T) {
prog := makeProgram(HASKEY)
vm := load(prog)
vm.estack.PushVal(1)
vm.estack.PushVal(2)
vm.Run()
assert.Equal(t, true, vm.HasFailed())
}
func TestSIGNNoArgument(t *testing.T) { func TestSIGNNoArgument(t *testing.T) {
prog := makeProgram(SIGN) prog := makeProgram(SIGN)
vm := load(prog) vm := load(prog)