Search Apps Documentation Source Content File Folder Download Copy Actions Download

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}