answer.gno
3.01 Kb · 99 lines
1package kourt
2const answerWindow = 3 * epochBlocks
3func PostAnswer(cur realm, courtSlug string, claimID uint64, verdict int) {
4 if !cur.IsCurrent() {
5 panic(errStaleRealm)
6 }
7 who := cur.Previous().Address()
8 c := mustCourt(courtSlug)
9 cs := mustClaim(c, claimID)
10 mustSide(verdict)
11 if cs.closed {
12 panic("kourtv2: this claim is closed")
13 }
14 if cs.frozenAt != 0 {
15 panic("kourtv2: this claim already has an answer")
16 }
17 now := heightNow()
18 if passed, known := pastDeadline(cs.openedAtTime, deadClaimSecs); (known && passed) ||
19 (!known && now >= cs.openedAt+deadClaimTimeout) {
20 panic("kourtv2: this claim is past the dead-claim timeout; it closes, it is not answered")
21 }
22 xbar, mature := cs.oi.Average(now, answerWindow)
23 if !mature {
24 panic("kourtv2: not enough stake history to answer yet")
25 }
26 if xbar < effMinAnswerX(c) {
27 panic("kourtv2: trailing stake is below the minimum to answer")
28 }
29 inPriority := false
30 if passed, known := pastDeadline(cs.openedAtTime,
31 blocksToSecs(c.params.stakeOpenDelayBlocks+answerWindow)+priorityWindowSecs); priorityGateActive(c) &&
32 ((known && !passed) ||
33 (!known && now < cs.openedAt+c.params.stakeOpenDelayBlocks+answerWindow+priorityWindowBlocks)) {
34 if !mayAnswerInPriority(c, who) {
35 panic("kourtv2: the priority window is open — a qualified answerer may act first (wait ~24h)")
36 }
37 inPriority = true
38 }
39 touch(c)
40 advancePools(c, cs)
41 if life := lifeAvgStake(cs, now); life > xbar {
42 xbar = life
43 }
44 bond := xbar * answerBondBps / 10000
45 if c.params.answerBondCapCC > 0 && bond > c.params.answerBondCapCC {
46 bond = c.params.answerBondCapCC
47 }
48 convHi, convLo := cs.sideConv(verdict)
49 floor := bondFloorAt(xbar, convHi, convLo)
50 oppHi, oppLo := cs.sideConv(oppositeSide(verdict))
51 if opp := bondFloorAt(xbar, oppHi, oppLo); opp > floor {
52 floor = opp
53 }
54 if floor > bond {
55 bond = floor
56 }
57 if bond < 1 {
58 bond = 1
59 }
60 mustSpendable(c, who, bond)
61 c.coin.Transfer(who, c.escrow, bond)
62 cs.frozenAt = now
63 cs.rateAccAtFreeze = c.rateAccFP
64 cs.xBarFrozen = xbar
65 cs.tierRef = tierRefAt(c)
66 observeClaimSize(c, xbar)
67 cs.yesStakeAtFreeze, cs.noStakeAtFreeze = cs.yesStake, cs.noStake
68 cs.answer = int8(verdict)
69 cs.answerer = who
70 cs.answerBond = bond
71 cs.answerBond0 = bond
72 cs.answerHeight = now
73 cs.answeredAtTime = nowTime()
74 if inPriority {
75 holdPriority(c, who, claimID)
76 }
77 pendingExit(c, cs)
78 stripEnter(c, cs)
79 onClaimAnswered(c, cs)
80}
81func HasAnswer(courtSlug string, claimID uint64) bool {
82 return mustClaim(mustCourt(courtSlug), claimID).frozenAt != 0
83}
84func AnswerVerdict(courtSlug string, claimID uint64) int {
85 cs := mustClaim(mustCourt(courtSlug), claimID)
86 if cs.frozenAt == 0 {
87 panic("kourtv2: no answer yet")
88 }
89 return int(cs.answer)
90}
91func AnswerBond(courtSlug string, claimID uint64) int64 {
92 return mustClaim(mustCourt(courtSlug), claimID).answerBond
93}
94func Answerer(courtSlug string, claimID uint64) address {
95 return mustClaim(mustCourt(courtSlug), claimID).answerer
96}
97func XBarFrozen(courtSlug string, claimID uint64) int64 {
98 return mustClaim(mustCourt(courtSlug), claimID).xBarFrozen
99}