votelock.gno
2.95 Kb · 124 lines
1package kourt
2import "gno.land/p/nt/bptree/v0"
3const (
4 voteLockDispute = "d"
5 voteLockElection = "e"
6)
7func voteLockKey(who address, kind string, id, sub uint64) string {
8 return string(who) + kind + beClaimKey(id) + beClaimKey(sub)
9}
10func voteLockParts(who address, key string) (kind string, id, sub uint64, ok bool) {
11 tail := key[len(string(who)):]
12 if len(tail) != 1+8+8 {
13 return "", 0, 0, false
14 }
15 return tail[0:1], beClaimID(tail[1:9]), beClaimID(tail[9:17]), true
16}
17func voteLockOpen(c *Court, who address, key string) bool {
18 kind, id, sub, ok := voteLockParts(who, key)
19 if !ok {
20 return false
21 }
22 switch kind {
23 case voteLockDispute:
24 v := c.claims.Get(beClaimKey(id))
25 if v == nil {
26 return false
27 }
28 cs := v.(*claimState)
29 return cs.disputeOpen && cs.proposalID == int64(sub)
30 case voteLockElection:
31 if c.mod == nil || c.mod.election == nil {
32 return false
33 }
34 e := c.mod.election
35 return e.seq == id && !e.resolved
36 }
37 return false
38}
39func voteLockedOf(c *Court, who address) int64 {
40 if c.voteLocks == nil {
41 return 0
42 }
43 var most int64
44 pre := string(who)
45 c.voteLocks.Iterate(pre, pre+"\xff", func(k string, v any) bool {
46 if w := v.(int64); w > most && voteLockOpen(c, who, k) {
47 most = w
48 }
49 return false
50 })
51 return most
52}
53func lockVote(c *Court, who address, kind string, id, sub, amount int64) {
54 if amount <= 0 {
55 return
56 }
57 if c.voteLocks == nil {
58 c.voteLocks = bptree.NewBPTree32()
59 }
60 pruneVoteLocks(c, who)
61 c.voteLocks.Set(voteLockKey(who, kind, uint64(id), uint64(sub)), amount)
62}
63func pruneVoteLocks(c *Court, who address) int {
64 if c.voteLocks == nil {
65 return 0
66 }
67 var stale []string
68 pre := string(who)
69 c.voteLocks.Iterate(pre, pre+"\xff", func(k string, _ any) bool {
70 if _, _, _, ok := voteLockParts(who, k); !ok {
71 return false
72 }
73 if !voteLockOpen(c, who, k) {
74 stale = append(stale, k)
75 }
76 return false
77 })
78 for _, k := range stale {
79 c.voteLocks.Remove(k)
80 }
81 return len(stale)
82}
83func beClaimID(s string) uint64 {
84 var v uint64
85 for i := 0; i < 8; i++ {
86 v = v<<8 | uint64(s[i])
87 }
88 return v
89}
90func PruneVoteLocks(cur realm, courtSlug string, who address) int {
91 if !cur.IsCurrent() {
92 panic(errStaleRealm)
93 }
94 if !who.IsValid() {
95 panic("kourtv2: that is not a valid address")
96 }
97 return pruneVoteLocks(mustCourt(courtSlug), who)
98}
99func CommitmentsOf(courtSlug string, who address) string {
100 c := mustCourt(courtSlug)
101 out := "stake:" + itoa(lockedOf(c, who)) +
102 ";vote:" + itoa(voteLockedOf(c, who)) +
103 ";free:" + itoa(disposable(c, who))
104 if c.voteLocks == nil {
105 return out
106 }
107 pre := string(who)
108 c.voteLocks.Iterate(pre, pre+"\xff", func(k string, v any) bool {
109 if !voteLockOpen(c, who, k) {
110 return false
111 }
112 kind, id, sub, ok := voteLockParts(who, k)
113 if !ok {
114 return false
115 }
116 out += ";q:" + kind + ":" + itoa(int64(id)) + ":" + itoa(int64(sub)) +
117 ":" + itoa(v.(int64))
118 return false
119 })
120 return out
121}
122func VoteLockedOf(courtSlug string, who address) int64 {
123 return voteLockedOf(mustCourt(courtSlug), who)
124}