From d069d4c82f22a943228fdcec84af8dd81c3d0d02 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Date: Mon, 8 Apr 2024 23:23:48 +0200 Subject: [PATCH 1/4] add Profile DataProvider --- .../worx_aggregator/providers/profile.gno | 23 ++++++++++ .../worx_aggregator/providers/profiles.gno | 39 +++++++++++++++++ .../providers/profiles_test.gno | 24 +++++++++++ .../r/demo/teritori/worx_aggregator/worx.gno | 43 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno new file mode 100644 index 00000000000..4849407e7d6 --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno @@ -0,0 +1,23 @@ +package provider + +import ( + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +type Profile struct{ + data avl.Tree +} + +func(p *Profile) ToString() string{ + var data = "" + p.data.Iterate("", "", func(key string, value interface{}) bool { + data += ufmt.Sprintf("%s: %s\n",key, value) + return false + }) + return data +} + +func(p *Profile) SetField(fieldName string, value string) { + p.data.Set(fieldName, value) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno new file mode 100644 index 00000000000..aef780696d1 --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno @@ -0,0 +1,39 @@ +package provider + +import ( + "std" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + +var profiles avl.Tree + +func Get(dataName string, addr std.Address) string { + if dataName != "profile"{ + panic("invalid dataname") + } + profile:=getProfile(addr) + + return profile.ToString() +} + +func SupportedTypes() []string{ + return []string{"profile"} +} + +func UpsertProfile(field string, value string){ + caller := std.GetOrigCaller() + profile := getProfile(caller) + profile.SetField(field, value) + profiles.Set(caller.String(), profile) +} + + +func getProfile(addr std.Address ) *Profile { + profile, found:=profiles.Get(addr.String()) + if !found{ + return &Profile{} + } + + return profile.(*Profile) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno new file mode 100644 index 00000000000..b3c02e9f1ec --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno @@ -0,0 +1,24 @@ +package provider + +import ( + "std" + "testing" + + "gno.land/p/demo/avl" + "gno.land/p/demo/testutils" + "strings" +) + +func TestGetProfile(t *testing.T) { + user1 := testutils.TestAddress("user1") + std.TestSetOrigCaller(user1) + UpsertProfile("firstname", "John") + UpsertProfile("name", "Gopher") + + result:=Get("profile",user1) + t.Log(result) + if !strings.Contains(result,"name: Gopher"){ + t.Error("Bad") + } + +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno new file mode 100644 index 00000000000..2a0f39e756a --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno @@ -0,0 +1,43 @@ +package worx_aggregator + +import( + "gno.land/p/demo/avl" +) + +//interface WorxDataProvider { +// Get(dataName string, addr std.Address) any +// SupportedTypes() []string +//} + +var admin std.Address +var dataProviders []WorxDataProvider +var dataTypeToDataProvider avl.Tree + + +func Get(dataType string, addr std.Address) []any { + all := []any{} + dataProviders := dataTypeToDataProvider.Get(dataType) + if len(dataProviders) == 0 { + panic("there is not dataprovider configured for that datatype") + } + for d := range dataProviders { + all = append(all, d.Get(dataType, addr)...) + } + return all +} + + +func RegisterDataProvider(dp WorxDataProvider) { + assertAdmin() + for supp := range dp.SupportedTypes() { + providers := dataTypeToDataProvider.Get(supp) + providers = append(providers, dp) + dataTypeToDataProvider.set(supp, providers) + } +} + +func assertAdmin(){ + if (std.PrevRealm().Addr() != admin) { + panic("unathorized") + } +} \ No newline at end of file From 7378d054f6b75b72e15c3235ec3db3cc35513631 Mon Sep 17 00:00:00 2001 From: Miguel Victoria Date: Tue, 9 Apr 2024 14:16:59 +0200 Subject: [PATCH 2/4] Change Pull -> Push --- .../gno.land/p/demo/teritori/worx/gno.mod | 1 + .../gno.land/p/demo/teritori/worx/worx.gno | 22 +++++++ .../gno.land/p/demo/teritori/worx/worxs.gno | 13 ++++ .../r/demo/teritori/providers/gno.mod | 6 ++ .../providers/profile.gno | 0 .../r/demo/teritori/providers/profiles.gno | 66 +++++++++++++++++++ .../providers/profiles_test.gno | 11 +++- .../r/demo/teritori/providers/worx_dao.gno | 18 +++++ .../r/demo/teritori/registry/registry.gno | 27 ++++++++ .../demo/teritori/registry/registry_test.gno | 22 +++++++ .../worx_aggregator/providers/profiles.gno | 39 ----------- .../r/demo/teritori/worx_aggregator/worx.gno | 57 +++++++++------- .../teritori/worx_aggregator/worx_test.gno | 16 +++++ 13 files changed, 235 insertions(+), 63 deletions(-) create mode 100644 examples/gno.land/p/demo/teritori/worx/gno.mod create mode 100644 examples/gno.land/p/demo/teritori/worx/worx.gno create mode 100644 examples/gno.land/p/demo/teritori/worx/worxs.gno create mode 100644 examples/gno.land/r/demo/teritori/providers/gno.mod rename examples/gno.land/r/demo/teritori/{worx_aggregator => }/providers/profile.gno (100%) create mode 100644 examples/gno.land/r/demo/teritori/providers/profiles.gno rename examples/gno.land/r/demo/teritori/{worx_aggregator => }/providers/profiles_test.gno (62%) create mode 100644 examples/gno.land/r/demo/teritori/providers/worx_dao.gno create mode 100644 examples/gno.land/r/demo/teritori/registry/registry.gno create mode 100644 examples/gno.land/r/demo/teritori/registry/registry_test.gno delete mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno diff --git a/examples/gno.land/p/demo/teritori/worx/gno.mod b/examples/gno.land/p/demo/teritori/worx/gno.mod new file mode 100644 index 00000000000..2c58c902520 --- /dev/null +++ b/examples/gno.land/p/demo/teritori/worx/gno.mod @@ -0,0 +1 @@ +module gno.land/p/demo/teritori/worx diff --git a/examples/gno.land/p/demo/teritori/worx/worx.gno b/examples/gno.land/p/demo/teritori/worx/worx.gno new file mode 100644 index 00000000000..82c2017204f --- /dev/null +++ b/examples/gno.land/p/demo/teritori/worx/worx.gno @@ -0,0 +1,22 @@ +package worx + +import "std" + + +type Worx struct { + Hours int + Metadata string + Address std.Address + Points int + Timestamp int64 +} + +func NewWorx(hours int, metadata string, addr std.Address, points int, timestamp int64) *Worx{ + return &Worx{ + Hours: hours, + Metadata: metadata, + Address: addr, + Points: points, + Timestamp: timestamp, + } +} \ No newline at end of file diff --git a/examples/gno.land/p/demo/teritori/worx/worxs.gno b/examples/gno.land/p/demo/teritori/worx/worxs.gno new file mode 100644 index 00000000000..359f3bba311 --- /dev/null +++ b/examples/gno.land/p/demo/teritori/worx/worxs.gno @@ -0,0 +1,13 @@ +package worx + +type WorxKeeper struct { + worxs []*Worx +} + +func (keeper *WorxKeeper) Store(worx *Worx) { + keeper.worxs = append(keeper.worxs, worx) +} + +func (keeper *WorxKeeper) Get() []*Worx { + return keeper.worxs +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/providers/gno.mod b/examples/gno.land/r/demo/teritori/providers/gno.mod new file mode 100644 index 00000000000..abc0c720f8e --- /dev/null +++ b/examples/gno.land/r/demo/teritori/providers/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/demo/teritori/social_follow + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest +) \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno b/examples/gno.land/r/demo/teritori/providers/profile.gno similarity index 100% rename from examples/gno.land/r/demo/teritori/worx_aggregator/providers/profile.gno rename to examples/gno.land/r/demo/teritori/providers/profile.gno diff --git a/examples/gno.land/r/demo/teritori/providers/profiles.gno b/examples/gno.land/r/demo/teritori/providers/profiles.gno new file mode 100644 index 00000000000..17cf28cd0aa --- /dev/null +++ b/examples/gno.land/r/demo/teritori/providers/profiles.gno @@ -0,0 +1,66 @@ +package provider + +import ( + "std" + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" + "gno.land/r/demo/teritori/registry" +) + +var profiles avl.Tree + +func init() { + registry.Register("profiles", RegisterHandler) +} + + +func Get(dataName string, addr std.Address) interface{} { + if dataName != "profile"{ + panic("invalid dataname") + } + profile:=getProfile(addr) + + return profile.ToString() +} + +func SupportedTypes() interface{}{ + return []interface{}{"profile"} +} + +func UpsertProfile(field string, value string){ + caller := std.GetOrigCaller() + profile := getProfile(caller) + profile.SetField(field, value) + profiles.Set(caller.String(), profile) +} + + +func getProfile(addr std.Address ) *Profile { + profile, found:=profiles.Get(addr.String()) + if !found{ + return &Profile{} + } + + return profile.(*Profile) +} + +func RegisterHandler(functionName string, args ...interface{}) interface{} { + switch functionName { + case "get": + if len(args) != 2{ + panic("invalid number of arguments") + } + dataname := args[0].(string) + address := args[1].(std.Address) + return Get(dataname,address) + case "supportedTypes": + if len(args) != 0{ + panic("invalid number of arguments") + } + dataname := args[0].(string) + address := args[1].(std.Address) + return SupportedTypes() + default: + panic("invalid function name") + } +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno b/examples/gno.land/r/demo/teritori/providers/profiles_test.gno similarity index 62% rename from examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno rename to examples/gno.land/r/demo/teritori/providers/profiles_test.gno index b3c02e9f1ec..b4e44e5f5c6 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles_test.gno +++ b/examples/gno.land/r/demo/teritori/providers/profiles_test.gno @@ -20,5 +20,14 @@ func TestGetProfile(t *testing.T) { if !strings.Contains(result,"name: Gopher"){ t.Error("Bad") } +} + +func TestRegisterHandler(t *testing.T) { + user1 := testutils.TestAddress("user1") + std.TestSetOrigCaller(user1) + supportedTypes := RegisterHandler("supportedTypes") + if len(supportedTypes) != 1{ + t.Error("Supported types is wrong") + } +} -} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/providers/worx_dao.gno b/examples/gno.land/r/demo/teritori/providers/worx_dao.gno new file mode 100644 index 00000000000..612374f74dc --- /dev/null +++ b/examples/gno.land/r/demo/teritori/providers/worx_dao.gno @@ -0,0 +1,18 @@ +package provider + +import ( + "std" + "gno.land/r/demo/teritori/worx_aggregator" + "gno.land/p/demo/rand" +) + +var admin std.Address + +func init() { + admin = std.GetOrigCaller() +} + +func RandWorx(addr std.Address){ + r := rand.New() + worx_aggregator.Push(r.Intn(25), "", addr, r.Intn(100), std.GetHeight()) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/registry/registry.gno b/examples/gno.land/r/demo/teritori/registry/registry.gno new file mode 100644 index 00000000000..faa6175fd9a --- /dev/null +++ b/examples/gno.land/r/demo/teritori/registry/registry.gno @@ -0,0 +1,27 @@ +package registry + +import ( + "gno.land/p/demo/avl" + "std" +) + +var callbacks avl.Tree +type FunctionCB func(functionName string, args ...interface{}) interface{} + +func Register(id string, callback FunctionCB){ + _,exists:=callbacks.Get(id) + if exists{ + panic("A callback already exists for the id") + } + + callbacks.Set(id, callback) +} + +func Exec(id string, functionName string, args ...interface{}) interface{} { + cb, ok:= callbacks.Get(id) + if !ok{ + panic("Callback not found") + } + function := cb.(FunctionCB) + return function(functionName, args) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/registry/registry_test.gno b/examples/gno.land/r/demo/teritori/registry/registry_test.gno new file mode 100644 index 00000000000..bb167cd1752 --- /dev/null +++ b/examples/gno.land/r/demo/teritori/registry/registry_test.gno @@ -0,0 +1,22 @@ +package registry + +import ( + "std" + "testing" + + "gno.land/p/demo/avl" + "gno.land/p/demo/testutils" + "strings" +) + +func TestGetProfile(t *testing.T) { + user1 := testutils.TestAddress("user1") + std.TestSetOrigCaller(user1) + functionID:="SOMEID" + var cb functionCB = func(args ...interface{})[]interface{}{ + //t.Errorf("dataType",dataType) + return nil + } + Register(functionID, cb) + Exec(functionID) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno deleted file mode 100644 index aef780696d1..00000000000 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/providers/profiles.gno +++ /dev/null @@ -1,39 +0,0 @@ -package provider - -import ( - "std" - "gno.land/p/demo/avl" - "gno.land/p/demo/ufmt" -) - -var profiles avl.Tree - -func Get(dataName string, addr std.Address) string { - if dataName != "profile"{ - panic("invalid dataname") - } - profile:=getProfile(addr) - - return profile.ToString() -} - -func SupportedTypes() []string{ - return []string{"profile"} -} - -func UpsertProfile(field string, value string){ - caller := std.GetOrigCaller() - profile := getProfile(caller) - profile.SetField(field, value) - profiles.Set(caller.String(), profile) -} - - -func getProfile(addr std.Address ) *Profile { - profile, found:=profiles.Get(addr.String()) - if !found{ - return &Profile{} - } - - return profile.(*Profile) -} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno index 2a0f39e756a..3b853bc6d11 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno @@ -2,38 +2,49 @@ package worx_aggregator import( "gno.land/p/demo/avl" + "gno.land/p/demo/teritori/worx" + "std" ) - -//interface WorxDataProvider { -// Get(dataName string, addr std.Address) any -// SupportedTypes() []string -//} - var admin std.Address -var dataProviders []WorxDataProvider -var dataTypeToDataProvider avl.Tree - - -func Get(dataType string, addr std.Address) []any { - all := []any{} - dataProviders := dataTypeToDataProvider.Get(dataType) - if len(dataProviders) == 0 { - panic("there is not dataprovider configured for that datatype") +var registeredProviders avl.Tree +var worxByAddress avl.Tree + +func Push(hours int, metadata string, addr std.Address, points int, timestamp int64) { + prevRealm := std.PrevRealm().Addr() + dataProviders, ok := registeredProviders.Get(string(prevRealm)) + if !ok { + panic("caller realm is not registered as provider") } - for d := range dataProviders { - all = append(all, d.Get(dataType, addr)...) + keeper := getKeeper(addr) + keeper.Store(worx.NewWorx(hours, metadata, addr, points, timestamp)) + worxByAddress.Set(string(addr), keeper) + + std.Emit("worx_added", + "addr",string(addr), + "metadata", metadata, + ) +} + +func getKeeper(addr std.Address) *worx.WorxKeeper{ + data, ok := worxByAddress.Get(string(addr)) + if ok { + return data.(*worx.WorxKeeper) } - return all + return &worx.WorxKeeper{} +} + +func Get(dataType string, addr std.Address) []*worx.Worx { + return getKeeper(addr).Get() } -func RegisterDataProvider(dp WorxDataProvider) { +func RegisterDataProvider(addr std.Address) { assertAdmin() - for supp := range dp.SupportedTypes() { - providers := dataTypeToDataProvider.Get(supp) - providers = append(providers, dp) - dataTypeToDataProvider.set(supp, providers) + _, ok :=registeredProviders.Get(string(addr)) + if !ok { + panic("Data provider already registered") } + registeredProviders.Set(string(addr), 0) } func assertAdmin(){ diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno new file mode 100644 index 00000000000..21ce9b75639 --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno @@ -0,0 +1,16 @@ +package worx_aggregator + +import ( + "testing" + "gno.land/p/demo/testutils" +) + +func TestPushCallerNotRegistered(t * testing.T){ + user1 := testutils.TestAddress("user1") + defer func() { + if v := recover(); v == nil { + t.Fatalf("expected panic got no error: ") + } + }() + Push(1, "", user1, 3, 10) +} From 296d1f5df2e4f39ee9674df3833b6d23a195de20 Mon Sep 17 00:00:00 2001 From: Omar Sy Date: Sun, 21 Apr 2024 18:27:58 +0200 Subject: [PATCH 3/4] feat: add aggregator --- .../gno.land/p/demo/teritori/worx/worxs.gno | 41 ++++++++- .../teritori/worx_aggregator/aggregator.gno | 17 ++++ .../r/demo/teritori/worx_aggregator/gno.mod | 5 ++ .../r/demo/teritori/worx_aggregator/worx.gno | 84 ++++++++++--------- 4 files changed, 105 insertions(+), 42 deletions(-) create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod diff --git a/examples/gno.land/p/demo/teritori/worx/worxs.gno b/examples/gno.land/p/demo/teritori/worx/worxs.gno index 359f3bba311..eaa2835133d 100644 --- a/examples/gno.land/p/demo/teritori/worx/worxs.gno +++ b/examples/gno.land/p/demo/teritori/worx/worxs.gno @@ -1,13 +1,50 @@ package worx +import ( + "gno.land/p/demo/avl" + "gno.land/p/demo/ufmt" +) + type WorxKeeper struct { worxs []*Worx } +const dayToSeconds = 1 + +func NewWorxKeeper() *WorxKeeper { + return &WorxKeeper{ + worxs: avl.NewTree(), + } +} + func (keeper *WorxKeeper) Store(worx *Worx) { keeper.worxs = append(keeper.worxs, worx) } func (keeper *WorxKeeper) Get() []*Worx { - return keeper.worxs -} \ No newline at end of file + totalWorx := make([]*Worx, 0) + keeper.worxs.Iterate("", "", func(key string, value interface{}) bool { + worxByDay := value.([]*Worx) + totalWorx = append(totalWorx, worxByDay...) + return false + }) + + return totalWorx +} + +func (keeper *WorxKeeper) GetFromDate(date int64) []*Worx { + start := ufmt.Sprintf("%d", date) + totalWorx := make([]*Worx, 0) + keeper.worxs.Iterate(start, "", func(key string, value interface{}) bool { + // here we account for string comparation "95" > "105" because comparing first character 9 > 1 (Comparation of lenght) + // and simply comparing same lenght string 25 > 12 this in order to stop tree for iterating over lower dates leaves + if len(start) > len(key) || start > key { + return true + } + worxByDay := value.([]*Worx) + totalWorx = append(totalWorx, worxByDay...) + return false + }) + + return totalWorx +} diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno new file mode 100644 index 00000000000..07c5727f76a --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno @@ -0,0 +1,17 @@ +package worx_aggregator + +import ( + "std" + + "gno.land/p/demo/teritori/worx" +) + +func GetWorx(addr std.Address) []*worx.Worx { + keeper := getKeeper(addr) + return keeper.Get() +} + +func GetWorxFromDate(addr std.Address, date int64) []*worx.Worx { + keeper := getKeeper(addr) + return keeper.GetFromDate(date) +} diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod b/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod new file mode 100644 index 00000000000..701b2f6b6cd --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod @@ -0,0 +1,5 @@ +module gno.land/r/demo/teritori/worx_aggregator + +require ( + gno.land/p/demo/teritori/worx v0.0.0-latest +) diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno index 3b853bc6d11..99432f3c1bd 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno @@ -1,54 +1,58 @@ package worx_aggregator -import( +import ( + "std" + "gno.land/p/demo/avl" - "gno.land/p/demo/teritori/worx" - "std" + "gno.land/p/demo/teritori/worx" +) + +var ( + admin std.Address + registeredProviders avl.Tree + worxByAddress avl.Tree ) -var admin std.Address -var registeredProviders avl.Tree -var worxByAddress avl.Tree func Push(hours int, metadata string, addr std.Address, points int, timestamp int64) { - prevRealm := std.PrevRealm().Addr() - dataProviders, ok := registeredProviders.Get(string(prevRealm)) - if !ok { - panic("caller realm is not registered as provider") - } - keeper := getKeeper(addr) - keeper.Store(worx.NewWorx(hours, metadata, addr, points, timestamp)) - worxByAddress.Set(string(addr), keeper) - - std.Emit("worx_added", - "addr",string(addr), - "metadata", metadata, - ) -} + assertRegistered(addr) -func getKeeper(addr std.Address) *worx.WorxKeeper{ - data, ok := worxByAddress.Get(string(addr)) - if ok { - return data.(*worx.WorxKeeper) - } - return &worx.WorxKeeper{} -} + keeper := getKeeper(addr) + keeper.Store(worx.NewWorx(hours, metadata, addr, points, timestamp)) + worxByAddress.Set(string(addr), keeper) -func Get(dataType string, addr std.Address) []*worx.Worx { - return getKeeper(addr).Get() + std.Emit("worx_added", + "addr", string(addr), + "metadata", metadata, + ) } +func getKeeper(addr std.Address) *worx.WorxKeeper { + data, ok := worxByAddress.Get(string(addr)) + if ok { + return data.(*worx.WorxKeeper) + } + return &worx.WorxKeeper{} +} func RegisterDataProvider(addr std.Address) { - assertAdmin() - _, ok :=registeredProviders.Get(string(addr)) - if !ok { - panic("Data provider already registered") - } - registeredProviders.Set(string(addr), 0) + assertAdmin() + _, ok := registeredProviders.Get(string(addr)) + if !ok { + panic("Data provider already registered") + } + registeredProviders.Set(string(addr), 0) +} + +func assertRegistered(addr std.Address) { + prevRealm := std.PrevRealm().Addr() + dataProviders, ok := registeredProviders.Get(string(prevRealm)) + if !ok { + panic("caller realm is not registered as provider") + } } -func assertAdmin(){ - if (std.PrevRealm().Addr() != admin) { - panic("unathorized") - } -} \ No newline at end of file +func assertAdmin() { + if std.PrevRealm().Addr() != admin { + panic("unathorized") + } +} From 56b0ed2434919e39879542dce90ac03b83741a32 Mon Sep 17 00:00:00 2001 From: Omar Sy Date: Sun, 21 Apr 2024 18:49:40 +0200 Subject: [PATCH 4/4] feat: add test --- examples/gno.land/Makefile | 70 +++++++++++++++++++ .../gno.land/p/demo/teritori/worx/worxs.gno | 14 +++- .../p/demo/teritori/worx/worxs_test.gno | 63 +++++++++++++++++ .../teritori/providers/random_pusher/gno.mod | 6 ++ .../providers/random_pusher/worx_dao.gno | 22 ++++++ .../r/demo/teritori/providers/worx_dao.gno | 18 ----- .../r/demo/teritori/worx_aggregator/admin.gno | 22 ++++++ .../teritori/worx_aggregator/aggregator.gno | 34 ++++++++- .../r/demo/teritori/worx_aggregator/gno.mod | 1 + .../r/demo/teritori/worx_aggregator/worx.gno | 41 ++++++----- .../teritori/worx_aggregator/worx_test.gno | 24 ++++++- 11 files changed, 276 insertions(+), 39 deletions(-) create mode 100644 examples/gno.land/Makefile create mode 100644 examples/gno.land/p/demo/teritori/worx/worxs_test.gno create mode 100644 examples/gno.land/r/demo/teritori/providers/random_pusher/gno.mod create mode 100644 examples/gno.land/r/demo/teritori/providers/random_pusher/worx_dao.gno delete mode 100644 examples/gno.land/r/demo/teritori/providers/worx_dao.gno create mode 100644 examples/gno.land/r/demo/teritori/worx_aggregator/admin.gno diff --git a/examples/gno.land/Makefile b/examples/gno.land/Makefile new file mode 100644 index 00000000000..8ca623a1296 --- /dev/null +++ b/examples/gno.land/Makefile @@ -0,0 +1,70 @@ +KEY = MyKey +BASE = teritori +REMOTE = http://127.0.0.1:26657 +CHAIN_ID = dev + +.PHONY: add_social_feeds_realm add_utf16_pkg add_ujson_pkg add_flags_index_pkg add_dao_interfaces_pkg add_social_feed all + +add_agregator_realm: + gnokey maketx addpkg \ + -deposit="1ugnot" \ + -gas-fee="1ugnot" \ + -gas-wanted="50000000" \ + -broadcast="true" \ + -chainid="${CHAIN_ID}" \ + -remote="${REMOTE}" \ + -pkgdir="./r/demo/teritori/worx_aggregator" \ + -pkgpath="gno.land/r/${BASE}/worx_aggregator" \ + ${KEY} + +add_random_worx_realm: + gnokey maketx addpkg \ + -deposit="1ugnot" \ + -gas-fee="1ugnot" \ + -gas-wanted="50000000" \ + -broadcast="true" \ + -chainid="${CHAIN_ID}" \ + -remote="${REMOTE}" \ + -pkgdir="./r/demo/teritori/providers/random_pusher" \ + -pkgpath="gno.land/r/${BASE}/providers/random_pusher" \ + ${KEY} + + +add_worx_pkg: + gnokey maketx addpkg \ + -deposit="1ugnot" \ + -gas-fee="1ugnot" \ + -gas-wanted="50000000" \ + -broadcast="true" \ + -chainid="${CHAIN_ID}" \ + -remote="${REMOTE}" \ + -pkgdir="./p/demo/teritori/worx" \ + -pkgpath="gno.land/p/${BASE}/worx" \ + ${KEY} + + +register_dataprovider: + gnokey maketx call \ + -pkgpath "gno.land/r/${BASE}/worx_aggregator" \ + -func="RegisterDataProvider" \ + -gas-fee="1000000ugnot" \ + -gas-wanted="3000000" \ + -remote="${REMOTE}" \ + -chainid="${CHAIN_ID}" \ + -broadcast \ + -args "gno.land/r/teritori/providers/random_pusher" \ + ${KEY} + +push_worx: + gnokey maketx call \ + -pkgpath "gno.land/r/${BASE}/providers/random_pusher" \ + -func="RandWorx" \ + -gas-fee="1000000ugnot" \ + -gas-wanted="3000000" \ + -remote="${REMOTE}" \ + -chainid="${CHAIN_ID}" \ + -broadcast \ + -args "g14vxq5e5pt5sev7rkz2ej438scmxtylnzv5vnkw" \ + ${KEY} + +all: add_utf16_pkg add_ujson_pkg add_flags_index_pkg add_dao_interfaces_pkg add_social_feeds_realm add_social_feed diff --git a/examples/gno.land/p/demo/teritori/worx/worxs.gno b/examples/gno.land/p/demo/teritori/worx/worxs.gno index eaa2835133d..fb2dfae7e87 100644 --- a/examples/gno.land/p/demo/teritori/worx/worxs.gno +++ b/examples/gno.land/p/demo/teritori/worx/worxs.gno @@ -3,10 +3,11 @@ package worx import ( "gno.land/p/demo/avl" "gno.land/p/demo/ufmt" + "time" ) type WorxKeeper struct { - worxs []*Worx + worxs *avl.Tree } const dayToSeconds = 1 @@ -18,7 +19,16 @@ func NewWorxKeeper() *WorxKeeper { } func (keeper *WorxKeeper) Store(worx *Worx) { - keeper.worxs = append(keeper.worxs, worx) + storekey := ufmt.Sprintf("%d", time.Now().Unix()) + worxs, ok:= keeper.worxs.Get(storekey) + if ok { + worxsOnDay := worxs.([]*Worx) + worxsOnDay = append(worxsOnDay, worx) + keeper.worxs.Set(storekey, worxsOnDay) + return + } + + keeper.worxs.Set(storekey, []*Worx{worx}) } func (keeper *WorxKeeper) Get() []*Worx { diff --git a/examples/gno.land/p/demo/teritori/worx/worxs_test.gno b/examples/gno.land/p/demo/teritori/worx/worxs_test.gno new file mode 100644 index 00000000000..ec3efab0e82 --- /dev/null +++ b/examples/gno.land/p/demo/teritori/worx/worxs_test.gno @@ -0,0 +1,63 @@ +package worx + +import ( + "testing" + "gno.land/p/demo/rand" + "gno.land/p/demo/testutils" + "gno.land/p/demo/ufmt" + "std" +) + +func TestAddGet(t *testing.T) { + keeper := NewWorxKeeper() + user1 := testutils.TestAddress("user1") + if len(keeper.Get()) != 0{ + t.Fatalf("Keeper is not empty initialized") + } + + fillRandomWorx(keeper, 10123423, user1) + if len(keeper.Get()) != 1{ + t.Fatalf("Keeper Worx was not added to keeper 1") + } + + fillRandomWorx(keeper, 10123423, user1) + if len(keeper.Get()) != 2{ + t.Fatalf("Keeper Worx was not added to keeper 2") + } +} + +func TestGetFromDate(t *testing.T) { + keeper := NewWorxKeeper() + user1 := testutils.TestAddress("user1") + if len(keeper.Get()) != 0{ + t.Fatalf("Keeper is not empty initialized") + } + + for i:=0; i < 100; i++ { + fillRandomWorx(keeper, int64(i*10), user1) + } + + if len(keeper.Get()) != 100{ + t.Fatalf("Keeper Worx was not totally added") + } + + if len(keeper.GetFromDate(1003)) != 0 { + t.Fatalf("Get From Date Should have found 0 registers") + } + + if len(keeper.GetFromDate(903)) != 9 { + t.Fatalf("Get From Date Should have found 9 registers") + } + +} + +func fillRandomWorx(keeper *WorxKeeper, timestamp int64, address std.Address){ + r := rand.New() + keeper.Store(NewWorx( + r.Intn(25), + "somekey", + address, + r.Intn(100), + timestamp, + )) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/providers/random_pusher/gno.mod b/examples/gno.land/r/demo/teritori/providers/random_pusher/gno.mod new file mode 100644 index 00000000000..0ca6bb1b4bb --- /dev/null +++ b/examples/gno.land/r/demo/teritori/providers/random_pusher/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/demo/teritori/random_pusher + +require ( + gno.land/p/demo/avl v0.0.0-latest + gno.land/p/demo/testutils v0.0.0-latest +) \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/providers/random_pusher/worx_dao.gno b/examples/gno.land/r/demo/teritori/providers/random_pusher/worx_dao.gno new file mode 100644 index 00000000000..245f24a130b --- /dev/null +++ b/examples/gno.land/r/demo/teritori/providers/random_pusher/worx_dao.gno @@ -0,0 +1,22 @@ +package random_pusher + +import ( + "std" + "gno.land/r/teritori/worx_aggregator" + "math/rand" +) + +var admin std.Address + +func init() { + admin = std.GetOrigCaller() + +} + +var rSeed = rand.NewPCG(0, 0) + +func RandWorx(addr std.Address){ + r := rand.New(rSeed) + + worx_aggregator.Push(r.IntN(25), "", addr, r.IntN(100), std.GetHeight()) +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/providers/worx_dao.gno b/examples/gno.land/r/demo/teritori/providers/worx_dao.gno deleted file mode 100644 index 612374f74dc..00000000000 --- a/examples/gno.land/r/demo/teritori/providers/worx_dao.gno +++ /dev/null @@ -1,18 +0,0 @@ -package provider - -import ( - "std" - "gno.land/r/demo/teritori/worx_aggregator" - "gno.land/p/demo/rand" -) - -var admin std.Address - -func init() { - admin = std.GetOrigCaller() -} - -func RandWorx(addr std.Address){ - r := rand.New() - worx_aggregator.Push(r.Intn(25), "", addr, r.Intn(100), std.GetHeight()) -} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/admin.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/admin.gno new file mode 100644 index 00000000000..bbc740e2124 --- /dev/null +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/admin.gno @@ -0,0 +1,22 @@ +package worx_aggregator + +import ( + "std" +) + +var adminAddr std.Address + +func assertIsAdmin() { + if std.PrevRealm().Addr() != adminAddr { + panic("restricted area") + } +} + +func setAdminAddress(address std.Address) { + adminAddr = address +} + +func SetAdminAddress(address std.Address) { + assertIsAdmin() + setAdminAddress(address) +} diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno index 07c5727f76a..d0124779dbb 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/aggregator.gno @@ -3,7 +3,10 @@ package worx_aggregator import ( "std" - "gno.land/p/demo/teritori/worx" + "gno.land/p/teritori/worx" + "strings" + + "gno.land/p/demo/ufmt" ) func GetWorx(addr std.Address) []*worx.Worx { @@ -15,3 +18,32 @@ func GetWorxFromDate(addr std.Address, date int64) []*worx.Worx { keeper := getKeeper(addr) return keeper.GetFromDate(date) } + +// Render renders the state of the realm +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + res := "Registered Dataproviders \n" + registeredProviders.Iterate("", "", func(key string, value interface{}) bool { + res += key + "\n" + return false + }) + + return res + case c == 1: + // Render worx for this address + owner := std.Address(parts[0]) + worxs := GetWorx(owner) + res := "user Worxs:\n" + for _, worx := range worxs { + res += ufmt.Sprintf(" Hours %d, Points %d, Timestamp %d \n",worx.Hours, worx.Points, worx.Timestamp) + } + + return res + default: + return "404\n" + } +} \ No newline at end of file diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod b/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod index 701b2f6b6cd..63d70821808 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/gno.mod @@ -2,4 +2,5 @@ module gno.land/r/demo/teritori/worx_aggregator require ( gno.land/p/demo/teritori/worx v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest ) diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno index 99432f3c1bd..e72e5075179 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx.gno @@ -4,17 +4,23 @@ import ( "std" "gno.land/p/demo/avl" - "gno.land/p/demo/teritori/worx" + "gno.land/p/teritori/worx" ) var ( - admin std.Address - registeredProviders avl.Tree - worxByAddress avl.Tree + registeredProviders *avl.Tree + worxByAddress *avl.Tree ) +func init() { + registeredProviders = avl.NewTree() + worxByAddress = avl.NewTree() + setAdminAddress(std.PrevRealm().Addr()) +} + func Push(hours int, metadata string, addr std.Address, points int, timestamp int64) { - assertRegistered(addr) + providerPath := std.PrevRealm().PkgPath() + assertRegistered(providerPath) keeper := getKeeper(addr) keeper.Store(worx.NewWorx(hours, metadata, addr, points, timestamp)) @@ -31,28 +37,29 @@ func getKeeper(addr std.Address) *worx.WorxKeeper { if ok { return data.(*worx.WorxKeeper) } - return &worx.WorxKeeper{} + return worx.NewWorxKeeper() +} + +func getDataProviderKeeper(packagePath string) *worx.WorxKeeper { + data, ok := registeredProviders.Get(packagePath) + if ok { + return data.(*worx.WorxKeeper) + } + return worx.NewWorxKeeper() } func RegisterDataProvider(addr std.Address) { - assertAdmin() + assertIsAdmin() _, ok := registeredProviders.Get(string(addr)) - if !ok { + if ok { panic("Data provider already registered") } registeredProviders.Set(string(addr), 0) } -func assertRegistered(addr std.Address) { - prevRealm := std.PrevRealm().Addr() - dataProviders, ok := registeredProviders.Get(string(prevRealm)) +func assertRegistered(packagePath string) { + _, ok := registeredProviders.Get(packagePath) if !ok { panic("caller realm is not registered as provider") } } - -func assertAdmin() { - if std.PrevRealm().Addr() != admin { - panic("unathorized") - } -} diff --git a/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno b/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno index 21ce9b75639..70ed2873666 100644 --- a/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno +++ b/examples/gno.land/r/demo/teritori/worx_aggregator/worx_test.gno @@ -1,11 +1,14 @@ package worx_aggregator import ( + "std" "testing" + + "gno.land/p/demo/avl" "gno.land/p/demo/testutils" ) -func TestPushCallerNotRegistered(t * testing.T){ +func TestPushCallerNotRegistered(t *testing.T) { user1 := testutils.TestAddress("user1") defer func() { if v := recover(); v == nil { @@ -14,3 +17,22 @@ func TestPushCallerNotRegistered(t * testing.T){ }() Push(1, "", user1, 3, 10) } + +func TestHappyPath(t *testing.T) { + registeredProviders = avl.NewTree() + worxByAddress = avl.NewTree() + + realm := testutils.TestAddress("realm") + admin := testutils.TestAddress("admin") + user1 := testutils.TestAddress("user1") + + setAdminAddress(admin) + + std.TestSetOrigCaller(admin) + + RegisterDataProvider(realm) + + std.TestSetOrigCaller(realm) + + Push(1, "", user1, 3, 10) +}