types.gno
4.22 Kb ยท 186 lines
1package memberstore
2
3import (
4 "errors"
5 "std"
6
7 "gno.land/p/demo/avl"
8)
9
10type ErrMemberAlreadyExists struct {
11 Tier string
12}
13
14func (e *ErrMemberAlreadyExists) Error() string {
15 return "member already exists on tier " + e.Tier
16}
17
18type Member struct {
19 InvitationPoints int
20}
21
22func (m *Member) RemoveInvitationPoint() {
23 if m.InvitationPoints <= 0 {
24 panic("not enough invitation points")
25 }
26
27 m.InvitationPoints = m.InvitationPoints - 1
28}
29
30// MembersByTier contains all `Member`s indexed by their Address.
31type MembersByTier struct {
32 *avl.Tree // tier name -> address -> member
33}
34
35func NewMembersByTier() MembersByTier {
36 return MembersByTier{Tree: avl.NewTree()}
37}
38
39func (mbt MembersByTier) DeleteAll() {
40 mbt.Iterate("", "", func(tn string, msv interface{}) bool {
41 mbt.Remove(tn)
42 return false
43 })
44}
45
46func (mbt MembersByTier) SetTier(tier string) error {
47 if ok := mbt.Has(tier); ok {
48 return errors.New("tier already exist: " + tier)
49 }
50
51 mbt.Set(tier, avl.NewTree())
52
53 return nil
54}
55
56// GetTierSize tries to get how many members are on the specified tier. If the tier does not exists, it returns 0.
57func (mbt MembersByTier) GetTierSize(tn string) int {
58 tv, ok := mbt.Get(tn)
59 if !ok {
60 return 0
61 }
62
63 tree, ok := tv.(*avl.Tree)
64 if !ok {
65 return 0
66 }
67
68 return tree.Size()
69}
70
71// SetMember adds a new member to the specified tier. The tier index is created on the fly if it does not exists.
72func (mbt MembersByTier) SetMember(tier string, addr std.Address, member *Member) error {
73 _, t := mbt.GetMember(addr)
74 if t != "" {
75 return &ErrMemberAlreadyExists{Tier: t}
76 }
77
78 if ok := mbt.Has(tier); !ok {
79 return errors.New("tier does not exist: " + tier)
80 }
81
82 ms, _ := mbt.Get(tier)
83 mst := ms.(*avl.Tree)
84
85 mst.Set(string(addr), member)
86
87 return nil
88}
89
90// GetMember iterate over all tiers to try to find a member by its address. The tier ID is also returned if the Member is found.
91func (mbt MembersByTier) GetMember(addr std.Address) (m *Member, t string) {
92 mbt.Iterate("", "", func(tn string, msv interface{}) bool {
93 mst, ok := msv.(*avl.Tree)
94 if !ok {
95 panic("MembersByTier values can only be avl.Tree")
96 }
97
98 mv, ok := mst.Get(string(addr))
99 if !ok {
100 return false
101 }
102
103 mm, ok := mv.(*Member)
104 if !ok {
105 panic("MembersByTier values can only be *Member")
106 }
107
108 m = mm
109 t = tn
110
111 return true
112 })
113
114 return
115}
116
117// RemoveMember removes a member from any tier
118func (mbt MembersByTier) RemoveMember(addr std.Address) (t string) {
119 mbt.Iterate("", "", func(tn string, msv interface{}) bool {
120 mst, ok := msv.(*avl.Tree)
121 if !ok {
122 panic("MembersByTier values can only be avl.Tree")
123 }
124
125 _, removed := mst.Remove(string(addr))
126 t = tn
127 return removed
128 })
129
130 return
131}
132
133// GetTotalPower obtains the total voting power from all the specified tiers.
134func (mbt MembersByTier) GetTotalPower() float64 {
135 var out float64
136 mbt.Iterate("", "", func(tn string, msv interface{}) bool {
137 tier, ok := Tiers.GetTier(tn)
138 if !ok {
139 // tier does not exists, so we cannot count power from this tier
140 return false
141 }
142
143 out = out + (tier.PowerHandler(mbt, Tiers) * float64(mbt.GetTierSize(tn)))
144
145 return false
146 })
147
148 return out
149}
150
151type Tier struct {
152 // BasePower defines the standard voting power for the members on this tier.
153 BasePower float64
154
155 // InvitationPoints defines how many invitation points users on that tier will receive.
156 InvitationPoints int
157
158 // MaxSize calculates the max amount of members expected to be on this tier.
159 MaxSize func(membersByTier MembersByTier, tiersByName TiersByName) int
160
161 // MinSize calculates the min amount of members expected to be on this tier.
162 MinSize func(membersByTier MembersByTier, tiersByName TiersByName) int
163
164 // PowerHandler calculates what is the final power of this tier after taking into account Members by other tiers.
165 PowerHandler func(membersByTier MembersByTier, tiersByName TiersByName) float64
166}
167
168// TiersByName contains all tier objects indexed by its name.
169type TiersByName struct {
170 *avl.Tree // *avl.Tree[string]Tier
171}
172
173// GetTier obtains a Tier struct by its name. It returns false if the Tier is not found.
174func (tbn TiersByName) GetTier(tn string) (Tier, bool) {
175 val, ok := tbn.Get(tn)
176 if !ok {
177 return Tier{}, false
178 }
179
180 t, ok := val.(Tier)
181 if !ok {
182 panic("TiersByName must contains only Tier types")
183 }
184
185 return t, true
186}