Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}