From 7156083b17f916c7513d40bdb795b43c8cd9d773 Mon Sep 17 00:00:00 2001 From: Blake <104744707+r3v4s@users.noreply.github.com> Date: Wed, 15 May 2024 15:50:23 +0900 Subject: [PATCH] feat: std.TestSetPrevRealm (#891) # Description Thanks to @albttx, we now have `std.PrevRealm` #667 However it seems like doesn't work on testcase(that can be run by `gno test` command) as what we expected. > `gno test` uses its own Context which makes few other functions (like GetRealmPath) doesn't work neither. So I made little helper very similar to `std.TestSetOrigCaller` --- ## Discussion Need `std.TestSetOrigCaller` takes single parameter and two different type can be passed 1. If `std.Address` type is passed, -> TestSetPrevRealm will take it as user address => return user address not realm. 2. If `string` type is passed, -> TestSetPrevRealm will take it as pkg_path => return pkg address(using bech32) and pkg_path > Since string parameter is being used without any verification in this pr, How about reusing verification logic from here ??https://github.com/gnolang/gno/blob/408fc68d4b3c189dbc6a608c590a86c661ae232a/tm2/pkg/std/memfile.go#L33-L68 ## 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 - [x] Added references to related issues and PRs - [ ] Provided any useful hints for running manual tests ## Maintainers Checklist - [x] Checked that the author followed the guidelines in `CONTRIBUTING.md` - [x] Checked the conventional-commit (especially PR title and verb, presence of `BREAKING CHANGE:` in the body) - [x] Ensured that this PR is not a significant change or confirmed that the review/consideration process was appropriate for the change --- examples/gno.land/r/x/test_prev/gno.mod | 8 ++++ examples/gno.land/r/x/test_prev/test_prev.gno | 18 ++++++++ .../gno.land/r/x/test_prev/test_prev_test.gno | 32 ++++++++++++++ gnovm/tests/stdlibs/native.go | 42 +++++++++++++++++++ gnovm/tests/stdlibs/std/std.gno | 4 ++ gnovm/tests/stdlibs/std/std.go | 17 ++++++++ 6 files changed, 121 insertions(+) create mode 100644 examples/gno.land/r/x/test_prev/gno.mod create mode 100644 examples/gno.land/r/x/test_prev/test_prev.gno create mode 100644 examples/gno.land/r/x/test_prev/test_prev_test.gno diff --git a/examples/gno.land/r/x/test_prev/gno.mod b/examples/gno.land/r/x/test_prev/gno.mod new file mode 100644 index 00000000000..de7d5d07e14 --- /dev/null +++ b/examples/gno.land/r/x/test_prev/gno.mod @@ -0,0 +1,8 @@ +module gno.land/r/x/test_prev + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/p/demo/users v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest +) diff --git a/examples/gno.land/r/x/test_prev/test_prev.gno b/examples/gno.land/r/x/test_prev/test_prev.gno new file mode 100644 index 00000000000..9466e5f96b9 --- /dev/null +++ b/examples/gno.land/r/x/test_prev/test_prev.gno @@ -0,0 +1,18 @@ +package test_prev + +import ( + "std" + + pusers "gno.land/p/demo/users" + "gno.land/r/demo/foo20" +) + +func DoSomeWithUserBalance() string { + caller := std.GetOrigCaller() + balance := foo20.BalanceOf(pusers.AddressOrName(caller)) + + if balance > 100 { + return "rich user" + } + return "poor user" +} diff --git a/examples/gno.land/r/x/test_prev/test_prev_test.gno b/examples/gno.land/r/x/test_prev/test_prev_test.gno new file mode 100644 index 00000000000..a6b86eafcb6 --- /dev/null +++ b/examples/gno.land/r/x/test_prev/test_prev_test.gno @@ -0,0 +1,32 @@ +package test_prev + +import ( + "std" + "testing" + + "gno.land/r/demo/foo20" +) + +func TestDoSomeWithUserBalancePoor(t *testing.T) { + std.TestSetOrigCaller("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") + if DoSomeWithUserBalance() != "poor user" { + t.Error("expected poor user") + } +} + +func TestDoSomeWithUserBalanceRichButPoor(t *testing.T) { + std.TestSetOrigCaller("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") + foo20.Faucet() // foo20 will mint tokens to this realm(std.PrevRealm) not user + if DoSomeWithUserBalance() != "poor user" { + t.Error("expected poor user") + } +} + +func TestDoSomeWithUserBalanceRich(t *testing.T) { + std.TestSetPrevAddr("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") + + foo20.Faucet() // foo20 will mint tokens to this realm not user + if DoSomeWithUserBalance() != "rich user" { + t.Error("expected rich user") + } +} diff --git a/gnovm/tests/stdlibs/native.go b/gnovm/tests/stdlibs/native.go index 6964a003025..81100838784 100644 --- a/gnovm/tests/stdlibs/native.go +++ b/gnovm/tests/stdlibs/native.go @@ -172,6 +172,48 @@ var nativeFuncs = [...]nativeFunc{ p0) }, }, + { + "std", + "testSetPrevRealm", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{}, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + + testlibs_std.X_testSetPrevRealm( + m, + p0) + }, + }, + { + "std", + "testSetPrevAddr", + []gno.FieldTypeExpr{ + {Name: gno.N("p0"), Type: gno.X("string")}, + }, + []gno.FieldTypeExpr{}, + func(m *gno.Machine) { + b := m.LastBlock() + var ( + p0 string + rp0 = reflect.ValueOf(&p0).Elem() + ) + + gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) + + testlibs_std.X_testSetPrevAddr( + m, + p0) + }, + }, { "std", "testSetOrigSend", diff --git a/gnovm/tests/stdlibs/std/std.gno b/gnovm/tests/stdlibs/std/std.gno index 2b142634740..0a4f9cc6eff 100644 --- a/gnovm/tests/stdlibs/std/std.gno +++ b/gnovm/tests/stdlibs/std/std.gno @@ -8,6 +8,8 @@ func ClearStoreCache() // injected func TestSetOrigCaller(addr Address) { testSetOrigCaller(string(addr)) } func TestSetOrigPkgAddr(addr Address) { testSetOrigPkgAddr(string(addr)) } +func TestSetPrevRealm(pkgPath string) { testSetPrevRealm(pkgPath) } +func TestSetPrevAddr(addr Address) { testSetPrevAddr(string(addr)) } func TestSetOrigSend(sent, spent Coins) { sentDenom, sentAmt := sent.expandNative() spentDenom, spentAmt := spent.expandNative() @@ -24,6 +26,8 @@ func callerAt(n int) string // native bindings func testSetOrigCaller(s string) func testSetOrigPkgAddr(s string) +func testSetPrevRealm(s string) +func testSetPrevAddr(s string) func testSetOrigSend( sentDenom []string, sentAmt []int64, spentDenom []string, spentAmt []int64) diff --git a/gnovm/tests/stdlibs/std/std.go b/gnovm/tests/stdlibs/std/std.go index f7bc001043e..72a2a7734ed 100644 --- a/gnovm/tests/stdlibs/std/std.go +++ b/gnovm/tests/stdlibs/std/std.go @@ -5,6 +5,8 @@ import ( "strings" "testing" + "github.com/gnolang/gno/gnovm/stdlibs" + gno "github.com/gnolang/gno/gnovm/pkg/gnolang" "github.com/gnolang/gno/gnovm/stdlibs/std" "github.com/gnolang/gno/tm2/pkg/crypto" @@ -100,6 +102,21 @@ func X_testSetOrigPkgAddr(m *gno.Machine, addr string) { m.Context = ctx } +func X_testSetPrevRealm(m *gno.Machine, pkgPath string) { + m.Frames[m.NumFrames()-2].LastPackage = &gno.PackageValue{PkgPath: pkgPath} +} + +func X_testSetPrevAddr(m *gno.Machine, addr string) { + // clear all frames to return mocked origin caller + for i := m.NumFrames() - 1; i > 0; i-- { + m.Frames[i].LastPackage = nil + } + + ctx := m.Context.(stdlibs.ExecContext) + ctx.OrigCaller = crypto.Bech32Address(addr) + m.Context = ctx +} + func X_testSetOrigSend(m *gno.Machine, sentDenom []string, sentAmt []int64, spentDenom []string, spentAmt []int64,