forked from TrueCloudLab/neoneo-go
vm: implement HASKEY opcode
This commit is contained in:
parent
df18da0ac9
commit
0fb4bb05cf
2 changed files with 127 additions and 1 deletions
33
pkg/vm/vm.go
33
pkg/vm/vm.go
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue