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}