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