Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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 := mbt.Get(tn)
 62	if tv == nil {
 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 := mst.Get(string(addr))
102		if mv == nil {
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 := tbn.Get(tn)
181	if val == nil {
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}