store.gno
9.44 Kb · 381 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 errors.New(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 errors.New(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 errors.New(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 := configs.Get(formatInt64Key(version))
118 if result == nil {
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 errors.New(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 errors.New(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 := proposals.Get(formatInt64Key(proposalID))
175 if result == nil {
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 errors.New(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 errors.New(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 := votingInfos.Get(formatInt64Key(proposalID))
231 if votingInfo == nil {
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 errors.New(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 errors.New(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 := userProposals.Get(user)
292 if result == nil {
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 errors.New(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 := userProposals.Get(user); existing != nil {
318 var ok bool
319 proposalIDs, ok = existing.([]int64)
320 if !ok {
321 panic(ufmt.Sprintf("failed to cast result to []int64: %T", existing))
322 }
323 }
324
325 // Add new proposal ID
326 proposalIDs = append(proposalIDs, proposalID)
327 userProposals.Set(user, proposalIDs)
328
329 return s.kvStore.Set(0, rlm, StoreKeyUserProposals.String(), userProposals)
330}
331
332func (s *governanceStore) RemoveUserProposal(_ int, rlm realm, user string, proposalID int64) error {
333 if !rlm.IsCurrent() {
334 return errors.New(ErrSpoofedRealm)
335 }
336
337 if !s.HasUserProposalsStoreKey() {
338 return errors.New("user proposals store key not found")
339 }
340
341 userProposals := s.GetUserProposals()
342 proposalIDsRaw := userProposals.Get(user)
343 // proposal already removed
344 if proposalIDsRaw == nil {
345 return nil
346 }
347
348 proposalIDs, ok := proposalIDsRaw.([]int64)
349 if !ok {
350 panic(ufmt.Sprintf("failed to cast result to []int64: %T", proposalIDs))
351 }
352
353 newProposalIDs := make([]int64, 0)
354
355 for _, id := range proposalIDs {
356 if id != proposalID {
357 newProposalIDs = append(newProposalIDs, id)
358 }
359 }
360
361 if len(newProposalIDs) == 0 {
362 userProposals.Remove(user)
363 } else {
364 userProposals.Set(user, newProposalIDs)
365 }
366
367 return s.kvStore.Set(0, rlm, StoreKeyUserProposals.String(), userProposals)
368}
369
370// NewGovernanceStore creates a new governance store instance with the provided KV store.
371// This function is used by the upgrade system to create storage instances for each implementation.
372func NewGovernanceStore(kvStore store.KVStore) IGovernanceStore {
373 return &governanceStore{
374 kvStore: kvStore,
375 }
376}
377
378// formatInt64Key formats int64 identifiers for storage keys.
379func formatInt64Key(id int64) string {
380 return strconv.FormatInt(id, 10)
381}