correctly handle proposal time
This commit is contained in:
parent
d0f3162fdc
commit
db15b4c218
3 changed files with 141 additions and 131 deletions
|
|
@ -339,15 +339,19 @@ unlock ps = builder
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
ProposalStartingTime s = defStartingTime
|
||||||
|
|
||||||
time = case ps.transactionParameters.timeRange of
|
time = case ps.transactionParameters.timeRange of
|
||||||
WhileVoting ->
|
WhileVoting ->
|
||||||
closedBoundedInterval
|
let lb = s + (def :: ProposalTimingConfig).draftTime
|
||||||
((def :: ProposalTimingConfig).draftTime + 1)
|
ub = lb + (def :: ProposalTimingConfig).votingTime
|
||||||
((def :: ProposalTimingConfig).votingTime - 1)
|
in closedBoundedInterval (lb + 1) (ub - 1)
|
||||||
AfterVoting ->
|
AfterVoting ->
|
||||||
closedBoundedInterval
|
let lb =
|
||||||
((def :: ProposalTimingConfig).votingTime + 1)
|
s + (def :: ProposalTimingConfig).draftTime
|
||||||
((def :: ProposalTimingConfig).lockingTime - 1)
|
+ (def :: ProposalTimingConfig).votingTime
|
||||||
|
ub = lb + (def :: ProposalTimingConfig).lockingTime
|
||||||
|
in closedBoundedInterval (lb + 1) (ub - 1)
|
||||||
|
|
||||||
sig = case ps.transactionParameters.signedBy of
|
sig = case ps.transactionParameters.signedBy of
|
||||||
Unknown -> defUnknown
|
Unknown -> defUnknown
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ import Agora.Proposal (
|
||||||
pwinner',
|
pwinner',
|
||||||
)
|
)
|
||||||
import Agora.Proposal.Time (
|
import Agora.Proposal.Time (
|
||||||
|
PPeriod (PDraftingPeriod, PExecutingPeriod, PLockingPeriod, PVotingPeriod),
|
||||||
|
PTimingRelation (PAfter, PWithin),
|
||||||
currentProposalTime,
|
currentProposalTime,
|
||||||
isDraftPeriod,
|
pgetRelation,
|
||||||
isExecutionPeriod,
|
pisWithin,
|
||||||
isLockingPeriod,
|
|
||||||
isVotingPeriod,
|
|
||||||
)
|
)
|
||||||
import Agora.Stake (
|
import Agora.Stake (
|
||||||
PStakeDatum,
|
PStakeDatum,
|
||||||
|
|
@ -232,8 +232,6 @@ proposalValidator =
|
||||||
]
|
]
|
||||||
txInfo
|
txInfo
|
||||||
|
|
||||||
currentTime <- pletC $ currentProposalTime # txInfoF.validRange
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
PSpending ((pfield @"_0" #) -> propsalInputRef) <-
|
PSpending ((pfield @"_0" #) -> propsalInputRef) <-
|
||||||
|
|
@ -292,6 +290,20 @@ proposalValidator =
|
||||||
|
|
||||||
--------------------------------------------------------------------------
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
getTimingRelation' <-
|
||||||
|
pletC $
|
||||||
|
let currentTime =
|
||||||
|
passertPJust # "Current time should be resolved"
|
||||||
|
#$ currentProposalTime # txInfoF.validRange
|
||||||
|
in pgetRelation
|
||||||
|
# proposalInputDatumF.timingConfig
|
||||||
|
# proposalInputDatumF.startingTime
|
||||||
|
# currentTime
|
||||||
|
|
||||||
|
let getTimingRelation = (getTimingRelation' #) . pcon
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------
|
||||||
|
|
||||||
-- Handle stake inputs/outputs.
|
-- Handle stake inputs/outputs.
|
||||||
|
|
||||||
-- Reslove stake datum if the given UTxO is a stake UTxO.
|
-- Reslove stake datum if the given UTxO is a stake UTxO.
|
||||||
|
|
@ -473,11 +485,7 @@ proposalValidator =
|
||||||
currentStatus #== pconstant VotingReady
|
currentStatus #== pconstant VotingReady
|
||||||
|
|
||||||
pguardC "Proposal time should be wthin the voting period" $
|
pguardC "Proposal time should be wthin the voting period" $
|
||||||
isVotingPeriod # proposalInputDatumF.timingConfig
|
pisWithin # getTimingRelation PVotingPeriod
|
||||||
# proposalInputDatumF.startingTime
|
|
||||||
#$ passertPJust
|
|
||||||
# "Should be able to get current time"
|
|
||||||
# currentTime
|
|
||||||
|
|
||||||
-- Ensure the transaction is voting to a valid 'ResultTag'(outcome).
|
-- Ensure the transaction is voting to a valid 'ResultTag'(outcome).
|
||||||
PProposalVotes voteMap <- pmatchC proposalInputDatumF.votes
|
PProposalVotes voteMap <- pmatchC proposalInputDatumF.votes
|
||||||
|
|
@ -557,15 +565,8 @@ proposalValidator =
|
||||||
# proposalInputDatumF.votes
|
# proposalInputDatumF.votes
|
||||||
# sctxF.inputStakes
|
# sctxF.inputStakes
|
||||||
|
|
||||||
currentTime' =
|
|
||||||
passertPJust
|
|
||||||
# "Should be able to get current time"
|
|
||||||
# currentTime
|
|
||||||
|
|
||||||
inVotingPeriod =
|
inVotingPeriod =
|
||||||
isVotingPeriod # proposalInputDatumF.timingConfig
|
pisWithin # getTimingRelation PVotingPeriod
|
||||||
# proposalInputDatumF.startingTime
|
|
||||||
# currentTime'
|
|
||||||
|
|
||||||
-- The votes can only change when the proposal still allows voting.
|
-- The votes can only change when the proposal still allows voting.
|
||||||
shouldUpdateVotes =
|
shouldUpdateVotes =
|
||||||
|
|
@ -599,24 +600,6 @@ proposalValidator =
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
PAdvanceProposal _ -> unTermCont $ do
|
PAdvanceProposal _ -> unTermCont $ do
|
||||||
currentTime' <-
|
|
||||||
pletC $
|
|
||||||
passertPJust
|
|
||||||
# "Should be able to get current time"
|
|
||||||
# currentTime
|
|
||||||
|
|
||||||
applyIs <- pletC $
|
|
||||||
plam $ \f ->
|
|
||||||
f
|
|
||||||
# proposalInputDatumF.timingConfig
|
|
||||||
# proposalInputDatumF.startingTime
|
|
||||||
# currentTime'
|
|
||||||
let inDraftPeriod = applyIs # isDraftPeriod
|
|
||||||
inVotingPeriod = applyIs # isVotingPeriod
|
|
||||||
inExecutionPeriod = applyIs # isExecutionPeriod
|
|
||||||
|
|
||||||
inLockedPeriod <- pletC $ applyIs # isLockingPeriod
|
|
||||||
|
|
||||||
proposalOutputStatus <-
|
proposalOutputStatus <-
|
||||||
pletC $
|
pletC $
|
||||||
pfromData $
|
pfromData $
|
||||||
|
|
@ -641,10 +624,8 @@ proposalValidator =
|
||||||
pmatch currentStatus $ \case
|
pmatch currentStatus $ \case
|
||||||
PDraft ->
|
PDraft ->
|
||||||
witnessStakes $ \sctxF -> do
|
witnessStakes $ \sctxF -> do
|
||||||
let notTooLate = inDraftPeriod
|
pmatchC (getTimingRelation PDraftingPeriod) >>= \case
|
||||||
|
PWithin -> do
|
||||||
pmatchC notTooLate >>= \case
|
|
||||||
PTrue -> do
|
|
||||||
pguardC "More cosigns than minimum amount" $
|
pguardC "More cosigns than minimum amount" $
|
||||||
punsafeCoerce (pfromData thresholdsF.toVoting) #<= sctxF.totalAmount
|
punsafeCoerce (pfromData thresholdsF.toVoting) #<= sctxF.totalAmount
|
||||||
|
|
||||||
|
|
@ -658,20 +639,15 @@ proposalValidator =
|
||||||
pguardC "Proposal status set to VotingReady" $
|
pguardC "Proposal status set to VotingReady" $
|
||||||
proposalOutputStatus #== pconstant VotingReady
|
proposalOutputStatus #== pconstant VotingReady
|
||||||
-- Too late: failed proposal, status set to 'Finished'.
|
-- Too late: failed proposal, status set to 'Finished'.
|
||||||
PFalse ->
|
PAfter ->
|
||||||
pguardC "Proposal should fail: not on time" $
|
pguardC "Proposal should fail: not on time" $
|
||||||
proposalOutputStatus #== pconstant Finished
|
proposalOutputStatus #== pconstant Finished
|
||||||
|
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
PVotingReady -> unTermCont $ do
|
PVotingReady -> unTermCont $ do
|
||||||
let notTooLate = inLockedPeriod
|
pmatchC (getTimingRelation PLockingPeriod) >>= \case
|
||||||
notTooEarly = pnot # inVotingPeriod
|
PWithin -> do
|
||||||
|
|
||||||
pguardC "Cannot advance ahead of time" notTooEarly
|
|
||||||
|
|
||||||
pmatchC notTooLate >>= \case
|
|
||||||
PTrue -> do
|
|
||||||
-- 'VotingReady' -> 'Locked'
|
-- 'VotingReady' -> 'Locked'
|
||||||
pguardC "Proposal status set to Locked" $
|
pguardC "Proposal status set to Locked" $
|
||||||
proposalOutputStatus #== pconstant Locked
|
proposalOutputStatus #== pconstant Locked
|
||||||
|
|
@ -681,7 +657,7 @@ proposalValidator =
|
||||||
#$ punsafeCoerce
|
#$ punsafeCoerce
|
||||||
$ pfromData thresholdsF.execute
|
$ pfromData thresholdsF.execute
|
||||||
-- Too late: failed proposal, status set to 'Finished'.
|
-- Too late: failed proposal, status set to 'Finished'.
|
||||||
PFalse ->
|
PAfter ->
|
||||||
pguardC "Proposal should fail: not on time" $
|
pguardC "Proposal should fail: not on time" $
|
||||||
proposalOutputStatus #== pconstant Finished
|
proposalOutputStatus #== pconstant Finished
|
||||||
|
|
||||||
|
|
@ -690,11 +666,6 @@ proposalValidator =
|
||||||
----------------------------------------------------------------
|
----------------------------------------------------------------
|
||||||
|
|
||||||
PLocked -> unTermCont $ do
|
PLocked -> unTermCont $ do
|
||||||
let notTooLate = inExecutionPeriod
|
|
||||||
notTooEarly = pnot # inLockedPeriod
|
|
||||||
|
|
||||||
pguardC "Not too early" notTooEarly
|
|
||||||
|
|
||||||
pguardC "Proposal status set to Finished" $
|
pguardC "Proposal status set to Finished" $
|
||||||
proposalOutputStatus #== pconstant Finished
|
proposalOutputStatus #== pconstant Finished
|
||||||
|
|
||||||
|
|
@ -710,12 +681,12 @@ proposalValidator =
|
||||||
# pfromData txInfoF.inputs
|
# pfromData txInfoF.inputs
|
||||||
|
|
||||||
pguardC "GST not moved if too late, moved otherwise" $
|
pguardC "GST not moved if too late, moved otherwise" $
|
||||||
pif
|
pmatch
|
||||||
notTooLate
|
(getTimingRelation PExecutingPeriod)
|
||||||
-- Not too late: GST should moved
|
( \case
|
||||||
pidentity
|
PWithin -> pidentity
|
||||||
-- Not too late: GST should not moved
|
PAfter -> pnot
|
||||||
pnot
|
)
|
||||||
# gstMoved
|
# gstMoved
|
||||||
|
|
||||||
pure $ popaque $ pconstant ()
|
pure $ popaque $ pconstant ()
|
||||||
|
|
|
||||||
|
|
@ -18,20 +18,21 @@ module Agora.Proposal.Time (
|
||||||
PProposalTimingConfig (..),
|
PProposalTimingConfig (..),
|
||||||
PProposalStartingTime (..),
|
PProposalStartingTime (..),
|
||||||
PMaxTimeRangeWidth (..),
|
PMaxTimeRangeWidth (..),
|
||||||
|
PTimingRelation (..),
|
||||||
|
PPeriod (..),
|
||||||
|
|
||||||
-- * Compute periods given config and starting time.
|
-- * Compute periods given config and starting time.
|
||||||
validateProposalStartingTime,
|
validateProposalStartingTime,
|
||||||
currentProposalTime,
|
currentProposalTime,
|
||||||
isDraftPeriod,
|
|
||||||
isVotingPeriod,
|
|
||||||
isLockingPeriod,
|
|
||||||
isExecutionPeriod,
|
|
||||||
pisProposalTimingConfigValid,
|
pisProposalTimingConfigValid,
|
||||||
pisMaxTimeRangeWidthValid,
|
pisMaxTimeRangeWidthValid,
|
||||||
|
pgetRelation,
|
||||||
|
pisWithin,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Agora.Utils (pcurrentTimeDuration)
|
import Agora.Utils (pcurrentTimeDuration)
|
||||||
import Control.Composition ((.*))
|
import Control.Composition ((.*))
|
||||||
|
import Data.Functor ((<&>))
|
||||||
import Plutarch.Api.V1 (
|
import Plutarch.Api.V1 (
|
||||||
PExtended (PFinite),
|
PExtended (PFinite),
|
||||||
PInterval (PInterval),
|
PInterval (PInterval),
|
||||||
|
|
@ -46,11 +47,11 @@ import Plutarch.DataRepr (
|
||||||
)
|
)
|
||||||
import Plutarch.Extra.Applicative (PApply (pliftA2))
|
import Plutarch.Extra.Applicative (PApply (pliftA2))
|
||||||
import Plutarch.Extra.Field (pletAll, pletAllC)
|
import Plutarch.Extra.Field (pletAll, pletAllC)
|
||||||
|
import Plutarch.Extra.IsData (PlutusTypeEnumData)
|
||||||
import Plutarch.Extra.Maybe (pjust, pmaybe, pnothing)
|
import Plutarch.Extra.Maybe (pjust, pmaybe, pnothing)
|
||||||
import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pmatchC)
|
import "liqwid-plutarch-extra" Plutarch.Extra.TermCont (pletC, pmatchC)
|
||||||
import Plutarch.Extra.Time (
|
import Plutarch.Extra.Time (
|
||||||
PCurrentTime (PCurrentTime),
|
PCurrentTime (PCurrentTime),
|
||||||
pisCurrentTimeWithin,
|
|
||||||
pisWithinCurrentTime,
|
pisWithinCurrentTime,
|
||||||
)
|
)
|
||||||
import Plutarch.Lift (
|
import Plutarch.Lift (
|
||||||
|
|
@ -388,74 +389,108 @@ currentProposalTime = phoistAcyclic $
|
||||||
mkTime = phoistAcyclic $ plam $ pcon .* PCurrentTime
|
mkTime = phoistAcyclic $ plam $ pcon .* PCurrentTime
|
||||||
pure $ pliftA2 # mkTime # lowerBound # upperBound
|
pure $ pliftA2 # mkTime # lowerBound # upperBound
|
||||||
|
|
||||||
{- | True if the 'PProposalTime' is in the draft period.
|
{- | Represent relation between current time and a given period.
|
||||||
|
|
||||||
@since 0.1.0
|
Note that the "before" relation isn't present due to the fact that
|
||||||
|
it's considered as an error in the proposal script.
|
||||||
|
|
||||||
|
@since 1.0.0
|
||||||
-}
|
-}
|
||||||
isDraftPeriod ::
|
data PTimingRelation (s :: S)
|
||||||
|
= PWithin
|
||||||
|
| PAfter
|
||||||
|
deriving stock
|
||||||
|
( -- | @since 1.0.0
|
||||||
|
Generic
|
||||||
|
, -- | @since 1.0.0
|
||||||
|
Enum
|
||||||
|
, -- | @since 1.0.0
|
||||||
|
Bounded
|
||||||
|
)
|
||||||
|
deriving anyclass
|
||||||
|
( -- | @since 1.0.0
|
||||||
|
PlutusType
|
||||||
|
)
|
||||||
|
|
||||||
|
-- | @since 1.0.0
|
||||||
|
instance DerivePlutusType PTimingRelation where
|
||||||
|
type DPTStrat _ = PlutusTypeEnumData
|
||||||
|
|
||||||
|
{- | Return truw if a relation is 'PWithin'.
|
||||||
|
|
||||||
|
@since 1.0.0
|
||||||
|
-}
|
||||||
|
pisWithin :: forall (s :: S). Term s (PTimingRelation :--> PBool)
|
||||||
|
pisWithin = phoistAcyclic $
|
||||||
|
plam $
|
||||||
|
flip pmatch $ \case
|
||||||
|
PWithin -> pconstant True
|
||||||
|
_ -> pconstant False
|
||||||
|
|
||||||
|
{- | Represent a proposal period.
|
||||||
|
|
||||||
|
@since 1.0.0
|
||||||
|
-}
|
||||||
|
data PPeriod (s :: S)
|
||||||
|
= PDraftingPeriod
|
||||||
|
| PVotingPeriod
|
||||||
|
| PLockingPeriod
|
||||||
|
| PExecutingPeriod
|
||||||
|
deriving stock
|
||||||
|
( -- | @since 1.0.0
|
||||||
|
Generic
|
||||||
|
, -- | @since 1.0.0
|
||||||
|
Enum
|
||||||
|
, -- | @since 1.0.0
|
||||||
|
Bounded
|
||||||
|
)
|
||||||
|
deriving anyclass
|
||||||
|
( -- | @since 1.0.0
|
||||||
|
PlutusType
|
||||||
|
)
|
||||||
|
|
||||||
|
-- | @since 1.0.0
|
||||||
|
instance DerivePlutusType PPeriod where
|
||||||
|
type DPTStrat _ = PlutusTypeEnumData
|
||||||
|
|
||||||
|
{- | Compute the relation between current time range and the given peroid,
|
||||||
|
providing the starting time and timing configuration of a proposal. If the
|
||||||
|
relation cannot be ddetermined, error out.
|
||||||
|
|
||||||
|
@since 1.0.0
|
||||||
|
-}
|
||||||
|
pgetRelation ::
|
||||||
forall (s :: S).
|
forall (s :: S).
|
||||||
Term
|
Term
|
||||||
s
|
s
|
||||||
( PProposalTimingConfig
|
( PProposalTimingConfig
|
||||||
:--> PProposalStartingTime
|
:--> PProposalStartingTime
|
||||||
:--> PProposalTime
|
:--> PProposalTime
|
||||||
:--> PBool
|
:--> PPeriod
|
||||||
|
:--> PTimingRelation
|
||||||
)
|
)
|
||||||
isDraftPeriod = phoistAcyclic $
|
pgetRelation = phoistAcyclic $
|
||||||
plam $ \config s' -> pmatch s' $ \(PProposalStartingTime s) ->
|
plam $ \config startingTime currentTime period -> unTermCont $ do
|
||||||
pisCurrentTimeWithin # s # (s + (pfield @"draftTime" # config))
|
configF <- pletAllC config
|
||||||
|
|
||||||
{- | True if the 'PProposalTime' is in the voting period.
|
PProposalStartingTime s <- pmatchC startingTime
|
||||||
|
PCurrentTime lb ub <- pmatchC currentTime
|
||||||
|
|
||||||
@since 0.1.0
|
dub <- pletC $ s + configF.draftTime
|
||||||
-}
|
vub <- pletC $ dub + configF.votingTime
|
||||||
isVotingPeriod ::
|
lub <- pletC $ vub + configF.lockingTime
|
||||||
forall (s :: S).
|
eub <- pletC $ lub + configF.executingTime
|
||||||
Term
|
|
||||||
s
|
|
||||||
( PProposalTimingConfig
|
|
||||||
:--> PProposalStartingTime
|
|
||||||
:--> PProposalTime
|
|
||||||
:--> PBool
|
|
||||||
)
|
|
||||||
isVotingPeriod = phoistAcyclic $
|
|
||||||
plam $ \config s' -> pmatch s' $ \(PProposalStartingTime s) ->
|
|
||||||
pletFields @'["draftTime", "votingTime"] config $ \f ->
|
|
||||||
pisCurrentTimeWithin # s # (s + f.draftTime + f.votingTime)
|
|
||||||
|
|
||||||
{- | True if the 'PProposalTime' is in the locking period.
|
(plb, pub) <-
|
||||||
|
pmatchC period
|
||||||
|
<&> ( \case
|
||||||
|
PDraftingPeriod -> (s, dub)
|
||||||
|
PVotingPeriod -> (dub, vub)
|
||||||
|
PLockingPeriod -> (vub, lub)
|
||||||
|
PExecutingPeriod -> (lub, eub)
|
||||||
|
)
|
||||||
|
|
||||||
@since 0.1.0
|
pure $
|
||||||
-}
|
pif (plb #<= lb #&& ub #<= pub) (pcon PWithin) $
|
||||||
isLockingPeriod ::
|
pif (pub #< lb) (pcon PAfter) $
|
||||||
forall (s :: S).
|
ptraceError "pgetRelation: too early or invalid current time"
|
||||||
Term
|
|
||||||
s
|
|
||||||
( PProposalTimingConfig
|
|
||||||
:--> PProposalStartingTime
|
|
||||||
:--> PProposalTime
|
|
||||||
:--> PBool
|
|
||||||
)
|
|
||||||
isLockingPeriod = phoistAcyclic $
|
|
||||||
plam $ \config s' -> pmatch s' $ \(PProposalStartingTime s) ->
|
|
||||||
pletFields @'["draftTime", "votingTime", "lockingTime"] config $ \f ->
|
|
||||||
pisCurrentTimeWithin # s # (s + f.draftTime + f.votingTime + f.lockingTime)
|
|
||||||
|
|
||||||
{- | True if the 'PProposalTime' is in the execution period.
|
|
||||||
|
|
||||||
@since 0.1.0
|
|
||||||
-}
|
|
||||||
isExecutionPeriod ::
|
|
||||||
forall (s :: S).
|
|
||||||
Term
|
|
||||||
s
|
|
||||||
( PProposalTimingConfig
|
|
||||||
:--> PProposalStartingTime
|
|
||||||
:--> PProposalTime
|
|
||||||
:--> PBool
|
|
||||||
)
|
|
||||||
isExecutionPeriod = phoistAcyclic $
|
|
||||||
plam $ \config s' -> pmatch s' $ \(PProposalStartingTime s) ->
|
|
||||||
pletFields @'["draftTime", "votingTime", "lockingTime", "executingTime"] config $ \f ->
|
|
||||||
pisCurrentTimeWithin # s
|
|
||||||
# (s + f.draftTime + f.votingTime + f.lockingTime + f.executingTime)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue