Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: user registry changes #3905

Merged
merged 10 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/boards/z_0_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var bid boards.BoardID

func init() {
std.TestSetRealm(std.NewUserRealm(std.Address("g1wymu47drhr0kuq2098m792lytgtj2nyx77yrsm"))) // so that CurrentRealm.Addr() matches OrigCaller
err := users.Register("gnouser123")
users.Register("gnouser123")

bid = boards.CreateBoard("test_board")
boards.CreateThread(bid, "First Post (title)", "Body of the first post. (body)")
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/groups/z_2_b_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ func main() {
}

// Error:
// user not found
// r/gnoland/users: non-user call
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/groups/z_2_d_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ func main() {
}

// Error:
// user not found
// r/gnoland/users: non-user call
2 changes: 1 addition & 1 deletion examples/gno.land/r/gnoland/users/users.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
)

var (
changelog = releases.NewChangelog("r/gnoland/users")
cd = std.ChainDomain()
changelog = releases.NewChangelog("r/gnoland/users")
)

const usersPrefix = "gno.land/r/gnoland/users/"
Expand Down
4 changes: 2 additions & 2 deletions examples/gno.land/r/gnoland/users/v1/admin.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (

var paused = false // XXX: replace with p/moul/authz

// NewSetPausedExecutor allows GovDAO to pause or unpause this realm
func NewSetPausedExecutor(newPausedValue bool) dao.Executor {
// ProposeNewPausedValue allows GovDAO to pause or unpause this realm
func ProposeNewPausedValue(newPausedValue bool) dao.Executor {
cb := func() error {
paused = newPausedValue
return nil
Expand Down
3 changes: 2 additions & 1 deletion examples/gno.land/r/gnoland/users/v1/errors.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
)

var (
ErrNonUserCall = errors.New("r/gnoland/users: non-user call")
ErrPaused = errors.New("r/gnoland/users: paused")
ErrInvalidPayment = ufmt.Errorf("r/gnoland/users: you need to send exactly %s ugnot", registerPrice)
ErrInvalidPayment = ufmt.Errorf("r/gnoland/users: you need to send exactly %d ugnot", registerPrice)
ErrInvalidUsername = errors.New("r/gnoland/users: invalid username")
)
18 changes: 9 additions & 9 deletions examples/gno.land/r/gnoland/users/v1/users.gno
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,33 @@ var (
reUsername = regexp.MustCompile(reValidUsername)
)

// Register registers a new username for the caller
// Register registers a new username for the caller.
// A valid username must start with a minimum of 3 letters,
// end with a minimum of 3 numbers, and be less than 20 chars long.
// All letters must be lowercase, and the only valid special char is `_`.
// Only calls from EOAs are supported.
func Register(username string) error {
std.AssertOriginCall()
func Register(username string) {
if !std.PreviousRealm().IsUser() {
panic(ErrNonUserCall)
}

if paused {
return ErrPaused
panic(ErrPaused)
}

if std.OriginSend().AmountOf("ugnot") != registerPrice {
return ErrInvalidPayment
panic(ErrInvalidPayment)
}

if matched := reUsername.MatchString(username); !matched {
return ErrInvalidUsername
panic(ErrInvalidUsername)
}

registrant := std.PreviousRealm().Address()
if err := susers.RegisterUser(username, registrant); err != nil {
return err
panic(err)
}

latestUsers.Append(username)
std.Emit("Registeration", "address", registrant.String(), "name", username)

return nil
}
59 changes: 46 additions & 13 deletions examples/gno.land/r/gnoland/users/v1/users_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ func TestRegister_Valid(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(aliceAddr))
std.TestSetOriginCaller(aliceAddr)

uassert.NoError(t, Register(alice))
uassert.NotPanics(t, func() {
Register(alice)
})

res, latest := susers.ResolveName(alice)

uassert.NotEqual(t, nil, res)
Expand All @@ -39,24 +42,54 @@ func TestRegister_Invalid(t *testing.T) {
std.TestSetOriginCaller(bobAddr)

// Invalid usernames
uassert.Error(t, Register("alice"), ErrInvalidUsername.Error()) // vanity
uassert.Error(t, Register(""), ErrInvalidUsername.Error()) // empty
uassert.Error(t, Register(" "), ErrInvalidUsername.Error()) // empty
uassert.Error(t, Register("123"), ErrInvalidUsername.Error()) // only numbers
uassert.Error(t, Register("alice&#($)"), ErrInvalidUsername.Error()) // non-allowed chars
uassert.Error(t, Register("Alice123"), ErrInvalidUsername.Error()) // upper-case
uassert.Error(t, Register("toolongusernametoolongusernametoolongusername123"),
ErrInvalidUsername.Error()) // too long
uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("alice") // vanity
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("") // empty
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register(" ") // empty
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("123") // empty
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("123") // only numbers
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("alice&#($)") // non-allowed chars
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("Alice123") // upper-case
})

uassert.PanicsWithMessage(t, ErrInvalidUsername.Error(), func() {
Register("toolongusernametoolongusernametoolongusername123") // too long
})

// Name taken
urequire.NoError(t, Register(bob))
uassert.Error(t, Register(bob), susers.ErrNameTaken.Error())
}
urequire.NotPanics(t, func() {
Register(bob)
})

uassert.PanicsWithMessage(t, susers.ErrNameTaken.Error(), func() {
Register(bob) // already registered
})
}
func TestRegister_InvalidPayment(t *testing.T) {
std.TestSetRealm(std.NewUserRealm(bobAddr))
std.TestSetOriginCaller(bobAddr)

std.TestSetOriginSend(std.NewCoins(std.NewCoin("ugnot", 12)), nil) // invalid payment amount
uassert.Error(t, Register("alice"), ErrInvalidPayment.Error()) // vanity

uassert.PanicsWithMessage(t, ErrInvalidPayment.Error(), func() {
Register(alice)
})
}
19 changes: 19 additions & 0 deletions examples/gno.land/r/sys/users/admin.gno
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@ func ProposeControllerRemoval(addr std.Address) dao.Executor {
return bridge.GovDAO().NewGovDAOExecutor(cb)
}

// ProposeControllerAdditionAndRemoval allows GovDAO to add a new caller and remove an old caller in the same proposal.
func ProposeControllerAdditionAndRemoval(toAdd, toRemove std.Address) dao.Executor {
cb := func() error {
err := addToWhitelist(toAdd)
if err != nil {
panic(err)
}

err = deleteFromwhitelist(toRemove)
if err != nil {
panic(err)
}

return nil
}

return bridge.GovDAO().NewGovDAOExecutor(cb)
}

// Helpers

func deleteFromwhitelist(addr std.Address) error {
Expand Down
3 changes: 3 additions & 0 deletions examples/gno.land/r/sys/users/users.gno
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,8 @@ func makeUserDataSafe(data any) any {
if cpy.deleted {
return nil
}

// Note: when requesting data from this AVL tree, (exists bool) will be true
// Even if the data is "deleted". This is currently unavoidable
return cpy
}
2 changes: 1 addition & 1 deletion gno.land/genesis/genesis_txs.jsonl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["administrator123"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AmG6kzznyo1uNqWPAYU6wDpsmzQKDaEOrVRaZ08vOyX0"},"signature":""}],"memo":""}}
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["zo_oma123"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A6yg5/iiktruezVw5vZJwLlGwyrvw8RlqOToTRMWXkE2"},"signature":""}],"memo":""}}
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1qpymzwx4l4cy6cerdyajp9ksvjsf20rk5y9rtt","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["zoo_ma123"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"A6yg5/iiktruezVw5vZJwLlGwyrvw8RlqOToTRMWXkE2"},"signature":""}],"memo":""}}
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1manfred47kzduec920z88wfr64ylksmdcedlf5","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["moul001"]}],"fee":{"gas_wanted":"2000000","gas_fee":"200000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AnK+a6mcFDjY6b/v6p7r8QFW1M1PgIoQxBgrwOoyY7v3"},"signature":""}],"memo":""}}
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1fj9jccm3zjnqspq7lp2g7lj4czyfq0s35600g9","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["piupiu123"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"Ar68lqbU2YC63fbMcYUtJhYO3/66APM/EqF7m0nUjGyz"},"signature":""}],"memo":""}}
{"tx": {"msg":[{"@type":"/vm.m_call","caller":"g1ds24jj9kqjcskd0gzu24r9e4n62ggye230zuv5","send":"1000000ugnot","pkg_path":"gno.land/r/gnoland/users/v1","func":"Register","args":["anarcher123"]}],"fee":{"gas_wanted":"2000000","gas_fee":"1000000ugnot"},"signatures":[{"pub_key":{"@type":"/tm.PubKeySecp256k1","value":"AjpLbKdQeH+yB/1OCB148l5GlRRrXma71hdA8EES3H7f"},"signature":""}],"memo":""}}
Expand Down
2 changes: 1 addition & 1 deletion gnovm/stdlibs/std/native.gno
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package std

// AssertOriginCall panics if the calling method is not invoked via a direct
// MsgCall. It panics for for other cases, like if the calling method
// MsgCall. It panics for other cases, like if the calling method
// is invoked by another method (even from the same realm or package).
// It also panic every time when the transaction is broadcasted via
// MsgRun.
Expand Down
Loading