mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-28 19:31:34 +00:00
vm: fix PACKMAP operation
Close #3613 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
parent
176593b31f
commit
9082c6ea1a
4 changed files with 49 additions and 8 deletions
|
@ -824,7 +824,8 @@ func NewMap() *Map {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMapWithValue returns a new Map object filled with the specified value.
|
// NewMapWithValue returns a new Map object filled with the specified value
|
||||||
|
// without value validation.
|
||||||
func NewMapWithValue(value []MapElement) *Map {
|
func NewMapWithValue(value []MapElement) *Map {
|
||||||
if value != nil {
|
if value != nil {
|
||||||
return &Map{
|
return &Map{
|
||||||
|
|
|
@ -219,7 +219,7 @@ func TestSerializeLimited(t *testing.T) {
|
||||||
bigMap := make([]MapElement, customLimit/2)
|
bigMap := make([]MapElement, customLimit/2)
|
||||||
for i := range bigMap {
|
for i := range bigMap {
|
||||||
bigMap[i] = MapElement{
|
bigMap[i] = MapElement{
|
||||||
Key: NewByteArray([]byte("key")),
|
Key: NewByteArray([]byte("key" + strconv.Itoa(i))),
|
||||||
Value: NewBool(true),
|
Value: NewBool(true),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
pkg/vm/vm.go
13
pkg/vm/vm.go
|
@ -1214,15 +1214,16 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
panic("invalid length")
|
panic("invalid length")
|
||||||
}
|
}
|
||||||
|
|
||||||
items := make([]stackitem.MapElement, n)
|
m := stackitem.NewMap()
|
||||||
for i := range n {
|
for range n {
|
||||||
key := v.estack.Pop()
|
key := v.estack.Pop()
|
||||||
validateMapKey(key)
|
|
||||||
val := v.estack.Pop().value
|
val := v.estack.Pop().value
|
||||||
items[i].Key = key.value
|
if key.Item() == nil {
|
||||||
items[i].Value = val
|
panic("no key found")
|
||||||
}
|
}
|
||||||
v.estack.PushItem(stackitem.NewMapWithValue(items))
|
m.Add(key.value, val)
|
||||||
|
}
|
||||||
|
v.estack.PushItem(m)
|
||||||
|
|
||||||
case opcode.PACKSTRUCT, opcode.PACK:
|
case opcode.PACKSTRUCT, opcode.PACK:
|
||||||
n := toInt(v.estack.Pop().BigInt())
|
n := toInt(v.estack.Pop().BigInt())
|
||||||
|
|
|
@ -2083,6 +2083,45 @@ func TestUNPACKBadNotArray(t *testing.T) {
|
||||||
runWithArgs(t, prog, nil, 1)
|
runWithArgs(t, prog, nil, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPACKMAPDuplicateKeys(t *testing.T) {
|
||||||
|
prog := makeProgram(opcode.PACKMAP)
|
||||||
|
vm := load(prog)
|
||||||
|
|
||||||
|
keys := []string{"duplicateKey", "uniqueKey", "duplicateKey", "anotherUniqueKey"}
|
||||||
|
values := []string{"value1", "value2", "value3", "value4"}
|
||||||
|
|
||||||
|
for i := range keys {
|
||||||
|
vm.estack.PushVal(values[i])
|
||||||
|
vm.estack.PushVal(keys[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.estack.PushVal(len(keys))
|
||||||
|
runVM(t, vm)
|
||||||
|
|
||||||
|
require.Equal(t, 1, vm.estack.Len())
|
||||||
|
packedItem := vm.estack.Pop().Item()
|
||||||
|
require.Equal(t, stackitem.MapT, packedItem.Type())
|
||||||
|
|
||||||
|
packedMap := packedItem.(*stackitem.Map)
|
||||||
|
require.Equal(t, 3, packedMap.Len())
|
||||||
|
|
||||||
|
expected := []stackitem.MapElement{
|
||||||
|
{
|
||||||
|
Key: stackitem.NewByteArray([]byte("anotherUniqueKey")),
|
||||||
|
Value: stackitem.NewByteArray([]byte("value4")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: stackitem.NewByteArray([]byte("duplicateKey")),
|
||||||
|
Value: stackitem.NewByteArray([]byte("value1")),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: stackitem.NewByteArray([]byte("uniqueKey")),
|
||||||
|
Value: stackitem.NewByteArray([]byte("value2")),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, expected, packedMap.Value())
|
||||||
|
}
|
||||||
|
|
||||||
func TestUNPACKGood(t *testing.T) {
|
func TestUNPACKGood(t *testing.T) {
|
||||||
prog := makeProgram(opcode.UNPACK)
|
prog := makeProgram(opcode.UNPACK)
|
||||||
elements := []int{55, 34, 42}
|
elements := []int{55, 34, 42}
|
||||||
|
|
Loading…
Reference in a new issue