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