mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-05-03 11:41:48 +00:00
vm: implement Neo.Iterator.* interops
This commit is contained in:
parent
3ff7fd5262
commit
5bc32b523a
5 changed files with 300 additions and 22 deletions
|
@ -333,13 +333,17 @@ func TestPushData4Good(t *testing.T) {
|
|||
assert.Equal(t, []byte{1, 2, 3}, vm.estack.Pop().Bytes())
|
||||
}
|
||||
|
||||
func getEnumeratorProg(n int) (prog []byte) {
|
||||
func getEnumeratorProg(n int, isIter bool) (prog []byte) {
|
||||
prog = append(prog, byte(opcode.TOALTSTACK))
|
||||
for i := 0; i < n; i++ {
|
||||
prog = append(prog, byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getSyscallProg("Neo.Enumerator.Next")...)
|
||||
prog = append(prog, byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getSyscallProg("Neo.Enumerator.Value")...)
|
||||
if isIter {
|
||||
prog = append(prog, byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getSyscallProg("Neo.Iterator.Key")...)
|
||||
}
|
||||
}
|
||||
prog = append(prog, byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getSyscallProg("Neo.Enumerator.Next")...)
|
||||
|
@ -356,8 +360,9 @@ func checkEnumeratorStack(t *testing.T, vm *VM, arr []StackItem) {
|
|||
}
|
||||
|
||||
func testIterableCreate(t *testing.T, typ string) {
|
||||
isIter := typ == "Iterator"
|
||||
prog := getSyscallProg("Neo." + typ + ".Create")
|
||||
prog = append(prog, getEnumeratorProg(2)...)
|
||||
prog = append(prog, getEnumeratorProg(2, isIter)...)
|
||||
|
||||
vm := load(prog)
|
||||
arr := []StackItem{
|
||||
|
@ -367,22 +372,34 @@ func testIterableCreate(t *testing.T, typ string) {
|
|||
vm.estack.Push(&Element{value: NewArrayItem(arr)})
|
||||
|
||||
runVM(t, vm)
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
arr[1], NewBoolItem(true),
|
||||
arr[0], NewBoolItem(true),
|
||||
})
|
||||
if isIter {
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
makeStackItem(1), arr[1], NewBoolItem(true),
|
||||
makeStackItem(0), arr[0], NewBoolItem(true),
|
||||
})
|
||||
} else {
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
arr[1], NewBoolItem(true),
|
||||
arr[0], NewBoolItem(true),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnumeratorCreate(t *testing.T) {
|
||||
testIterableCreate(t, "Enumerator")
|
||||
}
|
||||
|
||||
func TestEnumeratorConcat(t *testing.T) {
|
||||
prog := getSyscallProg("Neo.Enumerator.Create")
|
||||
func TestIteratorCreate(t *testing.T) {
|
||||
testIterableCreate(t, "Iterator")
|
||||
}
|
||||
|
||||
func testIterableConcat(t *testing.T, typ string) {
|
||||
isIter := typ == "Iterator"
|
||||
prog := getSyscallProg("Neo." + typ + ".Create")
|
||||
prog = append(prog, byte(opcode.SWAP))
|
||||
prog = append(prog, getSyscallProg("Neo.Enumerator.Create")...)
|
||||
prog = append(prog, getSyscallProg("Neo.Enumerator.Concat")...)
|
||||
prog = append(prog, getEnumeratorProg(3)...)
|
||||
prog = append(prog, getSyscallProg("Neo."+typ+".Create")...)
|
||||
prog = append(prog, getSyscallProg("Neo."+typ+".Concat")...)
|
||||
prog = append(prog, getEnumeratorProg(3, isIter)...)
|
||||
vm := load(prog)
|
||||
|
||||
arr := []StackItem{
|
||||
|
@ -394,11 +411,80 @@ func TestEnumeratorConcat(t *testing.T) {
|
|||
vm.estack.Push(&Element{value: NewArrayItem(arr[1:])})
|
||||
|
||||
runVM(t, vm)
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
arr[2], NewBoolItem(true),
|
||||
arr[1], NewBoolItem(true),
|
||||
arr[0], NewBoolItem(true),
|
||||
|
||||
if isIter {
|
||||
// Yes, this is how iterators are concatenated in reference VM
|
||||
// https://github.com/neo-project/neo/blob/master-2.x/neo.UnitTests/UT_ConcatenatedIterator.cs#L54
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
makeStackItem(1), arr[2], NewBoolItem(true),
|
||||
makeStackItem(0), arr[1], NewBoolItem(true),
|
||||
makeStackItem(0), arr[0], NewBoolItem(true),
|
||||
})
|
||||
} else {
|
||||
checkEnumeratorStack(t, vm, []StackItem{
|
||||
arr[2], NewBoolItem(true),
|
||||
arr[1], NewBoolItem(true),
|
||||
arr[0], NewBoolItem(true),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnumeratorConcat(t *testing.T) {
|
||||
testIterableConcat(t, "Enumerator")
|
||||
}
|
||||
|
||||
func TestIteratorConcat(t *testing.T) {
|
||||
testIterableConcat(t, "Iterator")
|
||||
}
|
||||
|
||||
func TestIteratorKeys(t *testing.T) {
|
||||
prog := getSyscallProg("Neo.Iterator.Create")
|
||||
prog = append(prog, getSyscallProg("Neo.Iterator.Keys")...)
|
||||
prog = append(prog, byte(opcode.TOALTSTACK), byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getEnumeratorProg(2, false)...)
|
||||
|
||||
v := load(prog)
|
||||
arr := NewArrayItem([]StackItem{
|
||||
NewBoolItem(false),
|
||||
NewBigIntegerItem(42),
|
||||
})
|
||||
v.estack.PushVal(arr)
|
||||
|
||||
runVM(t, v)
|
||||
|
||||
checkEnumeratorStack(t, v, []StackItem{
|
||||
NewBigIntegerItem(1), NewBoolItem(true),
|
||||
NewBigIntegerItem(0), NewBoolItem(true),
|
||||
})
|
||||
}
|
||||
|
||||
func TestIteratorValues(t *testing.T) {
|
||||
prog := getSyscallProg("Neo.Iterator.Create")
|
||||
prog = append(prog, getSyscallProg("Neo.Iterator.Values")...)
|
||||
prog = append(prog, byte(opcode.TOALTSTACK), byte(opcode.DUPFROMALTSTACK))
|
||||
prog = append(prog, getEnumeratorProg(2, false)...)
|
||||
|
||||
v := load(prog)
|
||||
m := NewMapItem()
|
||||
m.Add(NewBigIntegerItem(1), NewBoolItem(false))
|
||||
m.Add(NewByteArrayItem([]byte{32}), NewByteArrayItem([]byte{7}))
|
||||
v.estack.PushVal(m)
|
||||
|
||||
runVM(t, v)
|
||||
require.Equal(t, 5, v.estack.Len())
|
||||
require.Equal(t, NewBoolItem(false), v.estack.Peek(0).value)
|
||||
|
||||
// Map values can be enumerated in any order.
|
||||
i1, i2 := 1, 3
|
||||
if _, ok := v.estack.Peek(i1).value.(*BoolItem); !ok {
|
||||
i1, i2 = i2, i1
|
||||
}
|
||||
|
||||
require.Equal(t, NewBoolItem(false), v.estack.Peek(i1).value)
|
||||
require.Equal(t, NewByteArrayItem([]byte{7}), v.estack.Peek(i2).value)
|
||||
|
||||
require.Equal(t, NewBoolItem(true), v.estack.Peek(2).value)
|
||||
require.Equal(t, NewBoolItem(true), v.estack.Peek(4).value)
|
||||
}
|
||||
|
||||
func getSyscallProg(name string) (prog []byte) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue