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}