From 91ac58b8482f5dad7cfdae48e36ce6fc09a98bdf Mon Sep 17 00:00:00 2001 From: Blake <104744707+r3v4s@users.noreply.github.com> Date: Fri, 10 May 2024 01:06:10 +0900 Subject: [PATCH] fix(gnovm): map key deletion in realms (#2017) after value is delete in map by `delete(map, key)`, map variable wasn't updating it-self
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [ ] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [X] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [ ] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests - [ ] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--- .../gno.land/r/x/map_delete/map_delete.gno | 18 ++++++++ .../r/x/map_delete/map_delete_test.gno | 21 ++++++++++ .../cmd/gnoland/testdata/map-delete.txtar | 41 +++++++++++++++++++ gnovm/pkg/gnolang/uverse.go | 17 ++++++++ 4 files changed, 97 insertions(+) create mode 100644 examples/gno.land/r/x/map_delete/map_delete.gno create mode 100644 examples/gno.land/r/x/map_delete/map_delete_test.gno create mode 100644 gno.land/cmd/gnoland/testdata/map-delete.txtar diff --git a/examples/gno.land/r/x/map_delete/map_delete.gno b/examples/gno.land/r/x/map_delete/map_delete.gno new file mode 100644 index 00000000000..f7f89e8893d --- /dev/null +++ b/examples/gno.land/r/x/map_delete/map_delete.gno @@ -0,0 +1,18 @@ +package mapdelete + +var mapus map[uint64]string = make(map[uint64]string) + +func init() { + mapus[3] = "three" + mapus[5] = "five" + mapus[9] = "nine" +} + +func DeleteMap(k uint64) { + delete(mapus, k) +} + +func GetMap(k uint64) bool { + _, exist := mapus[k] + return exist +} diff --git a/examples/gno.land/r/x/map_delete/map_delete_test.gno b/examples/gno.land/r/x/map_delete/map_delete_test.gno new file mode 100644 index 00000000000..a0118befed2 --- /dev/null +++ b/examples/gno.land/r/x/map_delete/map_delete_test.gno @@ -0,0 +1,21 @@ +package mapdelete + +import ( + "testing" +) + +func TestGetMap(t *testing.T) { + if !(GetMap(3)) { + t.Error("Expected true, got ", GetMap(3)) + } +} + +func TestDeleteMap(t *testing.T) { + DeleteMap(3) +} + +func TestGetMapAfterDelete(t *testing.T) { + if GetMap(3) { + t.Error("Expected false, got ", GetMap(3)) + } +} diff --git a/gno.land/cmd/gnoland/testdata/map-delete.txtar b/gno.land/cmd/gnoland/testdata/map-delete.txtar new file mode 100644 index 00000000000..12783d46ac5 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/map-delete.txtar @@ -0,0 +1,41 @@ +gnoland start + +# add contract +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/mapdelete -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout OK! + +# delete map +gnokey maketx call -pkgpath gno.land/r/demo/mapdelete -func DeleteMap -args 3 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout OK! + +# check deletion +gnokey maketx call -pkgpath gno.land/r/demo/mapdelete -func GetMap -args 3 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout OK! +stdout 'false bool' +# XXX without patching uverse.go, expected stdout is +# stdout 'true bool' + + + +-- gno.mod -- +module gno.land/r/demo/mapdelete + +-- realm.gno -- +package mapdelete + +var mapus map[uint64]string = make(map[uint64]string) + +func init() { + mapus[3] = "three" + mapus[5] = "five" + mapus[9] = "nine" +} + +func DeleteMap(k uint64) { + delete(mapus, k) +} + +func GetMap(k uint64) bool { + _, exist := mapus[k] + return exist +} \ No newline at end of file diff --git a/gnovm/pkg/gnolang/uverse.go b/gnovm/pkg/gnolang/uverse.go index 9f836c789fe..df16ecf0ad9 100644 --- a/gnovm/pkg/gnolang/uverse.go +++ b/gnovm/pkg/gnolang/uverse.go @@ -709,7 +709,24 @@ func UverseNode() *PackageNode { switch cbt := baseOf(arg0.TV.T).(type) { case *MapType: mv := arg0.TV.V.(*MapValue) + val, ok := mv.GetValueForKey(m.Store, &itv) + if !ok { + return + } + + // delete mv.DeleteForKey(m.Store, &itv) + + if m.Realm != nil { + // mark key as deleted + keyObj := itv.GetFirstObject(m.Store) + m.Realm.DidUpdate(mv, keyObj, nil) + + // mark value as deleted + valObj := val.GetFirstObject(m.Store) + m.Realm.DidUpdate(mv, valObj, nil) + } + return case *NativeType: krv := reflect.New(cbt.Type.Key()).Elem()