Search Apps Documentation Source Content File Folder Download Copy Actions Download

store.gno

9.25 Kb · 380 lines
  1package governance
  2
  3import (
  4	"errors"
  5	"strconv"
  6
  7	"gno.land/p/gnoswap/store"
  8	bptree "gno.land/p/nt/bptree/v0"
  9	ufmt "gno.land/p/nt/ufmt/v0"
 10)
 11
 12type StoreKey string
 13
 14func (s StoreKey) String() string {
 15	return string(s)
 16}
 17
 18const (
 19	StoreKeyConfigCounter   StoreKey = "configCounter"   // Config version counter
 20	StoreKeyProposalCounter StoreKey = "proposalCounter" // Proposal ID counter
 21
 22	StoreKeyConfigs StoreKey = "configs" // Configurations BPTree
 23
 24	StoreKeyProposals StoreKey = "proposals" // Proposals BPTree
 25
 26	StoreKeyProposalUserVotingInfos StoreKey = "proposalUserVotingInfos" // Proposal voting infos BPTree
 27
 28	StoreKeyUserProposals StoreKey = "userProposals" // User proposals mapping BPTree
 29)
 30
 31type governanceStore struct {
 32	kvStore store.KVStore
 33}
 34
 35// Counter methods
 36func (s *governanceStore) HasConfigCounterStoreKey() bool {
 37	return s.kvStore.Has(StoreKeyConfigCounter.String())
 38}
 39
 40func (s *governanceStore) GetConfigCounter() *Counter {
 41	result, err := s.kvStore.Get(StoreKeyConfigCounter.String())
 42	if err != nil {
 43		panic(err)
 44	}
 45
 46	counter, ok := result.(*Counter)
 47	if !ok {
 48		panic(ufmt.Sprintf("failed to cast result to *Counter: %T", result))
 49	}
 50
 51	return counter
 52}
 53
 54func (s *governanceStore) SetConfigCounter(_ int, rlm realm, counter *Counter) error {
 55	if !rlm.IsCurrent() {
 56		return ErrSpoofedRealm
 57	}
 58
 59	return s.kvStore.Set(0, rlm, StoreKeyConfigCounter.String(), counter)
 60}
 61
 62func (s *governanceStore) HasProposalCounterStoreKey() bool {
 63	return s.kvStore.Has(StoreKeyProposalCounter.String())
 64}
 65
 66func (s *governanceStore) GetProposalCounter() *Counter {
 67	result, err := s.kvStore.Get(StoreKeyProposalCounter.String())
 68	if err != nil {
 69		panic(err)
 70	}
 71
 72	counter, ok := result.(*Counter)
 73	if !ok {
 74		panic(ufmt.Sprintf("failed to cast result to int64: %T", result))
 75	}
 76
 77	return counter
 78}
 79
 80func (s *governanceStore) SetProposalCounter(_ int, rlm realm, counter *Counter) error {
 81	if !rlm.IsCurrent() {
 82		return ErrSpoofedRealm
 83	}
 84
 85	return s.kvStore.Set(0, rlm, StoreKeyProposalCounter.String(), counter)
 86}
 87
 88// Configs methods
 89func (s *governanceStore) HasConfigsStoreKey() bool {
 90	return s.kvStore.Has(StoreKeyConfigs.String())
 91}
 92
 93func (s *governanceStore) GetConfigs() *bptree.BPTree {
 94	result, err := s.kvStore.Get(StoreKeyConfigs.String())
 95	if err != nil {
 96		panic(err)
 97	}
 98
 99	configs, ok := result.(*bptree.BPTree)
100	if !ok {
101		panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
102	}
103
104	return configs
105}
106
107func (s *governanceStore) SetConfigs(_ int, rlm realm, configs *bptree.BPTree) error {
108	if !rlm.IsCurrent() {
109		return ErrSpoofedRealm
110	}
111
112	return s.kvStore.Set(0, rlm, StoreKeyConfigs.String(), configs)
113}
114
115func (s *governanceStore) GetConfig(version int64) (Config, bool) {
116	configs := s.GetConfigs()
117	result, ok := configs.Get(formatInt64Key(version))
118	if !ok {
119		return Config{}, false
120	}
121
122	config, ok := result.(Config)
123	if !ok {
124		panic(ufmt.Sprintf("failed to cast result to Config: %T", result))
125	}
126
127	return config, true
128}
129
130func (s *governanceStore) SetConfig(_ int, rlm realm, version int64, config Config) error {
131	if !rlm.IsCurrent() {
132		return ErrSpoofedRealm
133	}
134
135	if !s.HasConfigsStoreKey() {
136		return errors.New("configs store key not found")
137	}
138
139	configs := s.GetConfigs()
140	configs.Set(formatInt64Key(version), config)
141
142	return s.kvStore.Set(0, rlm, StoreKeyConfigs.String(), configs)
143}
144
145// Proposals methods
146func (s *governanceStore) HasProposalsStoreKey() bool {
147	return s.kvStore.Has(StoreKeyProposals.String())
148}
149
150func (s *governanceStore) GetProposals() *bptree.BPTree {
151	result, err := s.kvStore.Get(StoreKeyProposals.String())
152	if err != nil {
153		panic(err)
154	}
155
156	proposals, ok := result.(*bptree.BPTree)
157	if !ok {
158		panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
159	}
160
161	return proposals
162}
163
164func (s *governanceStore) SetProposals(_ int, rlm realm, proposals *bptree.BPTree) error {
165	if !rlm.IsCurrent() {
166		return ErrSpoofedRealm
167	}
168
169	return s.kvStore.Set(0, rlm, StoreKeyProposals.String(), proposals)
170}
171
172func (s *governanceStore) GetProposal(proposalID int64) (*Proposal, bool) {
173	proposals := s.GetProposals()
174	result, ok := proposals.Get(formatInt64Key(proposalID))
175	if !ok {
176		return nil, false
177	}
178
179	proposal, ok := result.(*Proposal)
180	if !ok {
181		return nil, false
182	}
183	return proposal, true
184}
185
186func (s *governanceStore) SetProposal(_ int, rlm realm, proposalID int64, proposal *Proposal) error {
187	if !rlm.IsCurrent() {
188		return ErrSpoofedRealm
189	}
190
191	if !s.HasProposalsStoreKey() {
192		return errors.New("proposals store key not found")
193	}
194
195	proposals := s.GetProposals()
196	proposals.Set(formatInt64Key(proposalID), proposal)
197
198	return s.kvStore.Set(0, rlm, StoreKeyProposals.String(), proposals)
199}
200
201// Proposal User Voting Infos methods
202func (s *governanceStore) HasProposalUserVotingInfosStoreKey() bool {
203	return s.kvStore.Has(StoreKeyProposalUserVotingInfos.String())
204}
205
206func (s *governanceStore) GetProposalUserVotingInfos() *bptree.BPTree {
207	result, err := s.kvStore.Get(StoreKeyProposalUserVotingInfos.String())
208	if err != nil {
209		panic(err)
210	}
211
212	votingInfos, ok := result.(*bptree.BPTree)
213	if !ok {
214		panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
215	}
216
217	return votingInfos
218}
219
220func (s *governanceStore) SetProposalUserVotingInfos(_ int, rlm realm, votingInfos *bptree.BPTree) error {
221	if !rlm.IsCurrent() {
222		return ErrSpoofedRealm
223	}
224
225	return s.kvStore.Set(0, rlm, StoreKeyProposalUserVotingInfos.String(), votingInfos)
226}
227
228func (s *governanceStore) GetProposalVotingInfos(proposalID int64) (*bptree.BPTree, bool) {
229	votingInfos := s.GetProposalUserVotingInfos()
230	votingInfo, ok := votingInfos.Get(formatInt64Key(proposalID))
231	if !ok {
232		return nil, false
233	}
234
235	votingInfoTree, ok := votingInfo.(*bptree.BPTree)
236	if !ok {
237		return nil, false
238	}
239
240	return votingInfoTree, true
241}
242
243func (s *governanceStore) SetProposalVotingInfos(_ int, rlm realm, proposalID int64, votingInfos *bptree.BPTree) error {
244	if !rlm.IsCurrent() {
245		return ErrSpoofedRealm
246	}
247
248	if !s.HasProposalUserVotingInfosStoreKey() {
249		return errors.New("proposal user voting infos store key not found")
250	}
251
252	allVotingInfos := s.GetProposalUserVotingInfos()
253	allVotingInfos.Set(formatInt64Key(proposalID), votingInfos)
254
255	return s.kvStore.Set(0, rlm, StoreKeyProposalUserVotingInfos.String(), allVotingInfos)
256}
257
258// User Proposals methods
259func (s *governanceStore) HasUserProposalsStoreKey() bool {
260	return s.kvStore.Has(StoreKeyUserProposals.String())
261}
262
263func (s *governanceStore) GetUserProposals() *bptree.BPTree {
264	result, err := s.kvStore.Get(StoreKeyUserProposals.String())
265	if err != nil {
266		panic(err)
267	}
268
269	userProposals, ok := result.(*bptree.BPTree)
270	if !ok {
271		panic(ufmt.Sprintf("failed to cast result to *bptree.BPTree: %T", result))
272	}
273
274	return userProposals
275}
276
277func (s *governanceStore) SetUserProposals(_ int, rlm realm, userProposals *bptree.BPTree) error {
278	if !rlm.IsCurrent() {
279		return ErrSpoofedRealm
280	}
281
282	return s.kvStore.Set(0, rlm, StoreKeyUserProposals.String(), userProposals)
283}
284
285func (s *governanceStore) GetUserProposalsTree() *bptree.BPTree {
286	return s.GetUserProposals()
287}
288
289func (s *governanceStore) GetUserProposalIDs(user string) ([]int64, bool) {
290	userProposals := s.GetUserProposals()
291	result, ok := userProposals.Get(user)
292	if !ok {
293		return nil, false
294	}
295
296	proposalIDs, ok := result.([]int64)
297	if !ok {
298		panic(ufmt.Sprintf("failed to cast result to []int64: %T", result))
299	}
300
301	return proposalIDs, true
302}
303
304func (s *governanceStore) AddUserProposal(_ int, rlm realm, user string, proposalID int64) error {
305	if !rlm.IsCurrent() {
306		return ErrSpoofedRealm
307	}
308
309	if !s.HasUserProposalsStoreKey() {
310		return errors.New("user proposals store key not found")
311	}
312
313	userProposals := s.GetUserProposals()
314
315	// Get existing proposals for user
316	var proposalIDs []int64
317	if existing, ok := userProposals.Get(user); ok {
318		proposalIDs, ok = existing.([]int64)
319		if !ok {
320			panic(ufmt.Sprintf("failed to cast result to []int64: %T", existing))
321		}
322	}
323
324	// Add new proposal ID
325	proposalIDs = append(proposalIDs, proposalID)
326	userProposals.Set(user, proposalIDs)
327
328	return s.kvStore.Set(0, rlm, StoreKeyUserProposals.String(), userProposals)
329}
330
331func (s *governanceStore) RemoveUserProposal(_ int, rlm realm, user string, proposalID int64) error {
332	if !rlm.IsCurrent() {
333		return ErrSpoofedRealm
334	}
335
336	if !s.HasUserProposalsStoreKey() {
337		return errors.New("user proposals store key not found")
338	}
339
340	userProposals := s.GetUserProposals()
341	proposalIDsRaw, ok := userProposals.Get(user)
342	// proposal already removed
343	if !ok {
344		return nil
345	}
346
347	proposalIDs, ok := proposalIDsRaw.([]int64)
348	if !ok {
349		panic(ufmt.Sprintf("failed to cast result to []int64: %T", proposalIDs))
350	}
351
352	newProposalIDs := make([]int64, 0)
353
354	for _, id := range proposalIDs {
355		if id != proposalID {
356			newProposalIDs = append(newProposalIDs, id)
357		}
358	}
359
360	if len(newProposalIDs) == 0 {
361		userProposals.Remove(user)
362	} else {
363		userProposals.Set(user, newProposalIDs)
364	}
365
366	return s.kvStore.Set(0, rlm, StoreKeyUserProposals.String(), userProposals)
367}
368
369// NewGovernanceStore creates a new governance store instance with the provided KV store.
370// This function is used by the upgrade system to create storage instances for each implementation.
371func NewGovernanceStore(kvStore store.KVStore) IGovernanceStore {
372	return &governanceStore{
373		kvStore: kvStore,
374	}
375}
376
377// formatInt64Key formats int64 identifiers for storage keys.
378func formatInt64Key(id int64) string {
379	return strconv.FormatInt(id, 10)
380}