vm: fix PACKMAP operation

Close #3613

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2024-11-19 13:48:58 +03:00
parent 176593b31f
commit 9082c6ea1a
4 changed files with 49 additions and 8 deletions

View file

@ -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{

View file

@ -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),
} }
} }

View file

@ -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")
}
m.Add(key.value, val)
} }
v.estack.PushItem(stackitem.NewMapWithValue(items)) 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())

View file

@ -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}