fix governor datum validation

This commit is contained in:
Hongrui Fang 2022-07-15 21:17:54 +08:00
parent e22bdc59fb
commit d709a1fdd0
7 changed files with 289 additions and 218 deletions

View file

@ -23,7 +23,7 @@ import Agora.Governor (
Governor,
GovernorDatum,
PGovernorDatum,
governorDatumValid,
pisGovernorDatumValid,
)
import Agora.Governor.Scripts (
authorityTokenSymbolFromGovernor,
@ -215,7 +215,7 @@ mutateGovernorValidator gov = makeEffect (authorityTokenSymbolFromGovernor gov)
-- Ensure the output governor datum is what we want.
pguardC "Unexpected governor datum" $ datumF.newDatum #== governorOutputDatum
pguardC "New governor datum should be valid" $ governorDatumValid # governorOutputDatum
pguardC "New governor datum should be valid" $ pisGovernorDatumValid # governorOutputDatum
return $ popaque $ pconstant ()
where

View file

@ -20,7 +20,7 @@ module Agora.Governor (
-- * Utilities
pgetNextProposalId,
getNextProposalId,
governorDatumValid,
pisGovernorDatumValid,
) where
import Agora.Proposal (
@ -28,12 +28,15 @@ import Agora.Proposal (
PProposalThresholds (..),
ProposalId (ProposalId),
ProposalThresholds,
pisProposalThresholdsValid,
)
import Agora.Proposal.Time (
MaxTimeRangeWidth,
PMaxTimeRangeWidth,
PProposalTimingConfig,
ProposalTimingConfig,
pisMaxTimeRangeWidthValid,
pisProposalTimeingConfigValid,
)
import Agora.SafeMoney (GTTag)
import Data.Tagged (Tagged (..))
@ -44,15 +47,13 @@ import Plutarch.DataRepr (
PDataFields,
PIsDataReprInstances (PIsDataReprInstances),
)
import Plutarch.Extra.Comonad (pextract)
import Plutarch.Extra.IsData (
DerivePConstantViaEnum (..),
EnumIsData (..),
)
import Plutarch.Extra.Other (DerivePNewtype' (..))
import Plutarch.Extra.TermCont (pletC, pletFieldsC, pmatchC)
import Plutarch.Extra.TermCont (pletFieldsC)
import Plutarch.Lift (PConstantDecl, PUnsafeLiftDecl (..))
import Plutarch.SafeMoney (PDiscrete (..))
import PlutusLedgerApi.V1 (TxOutRef)
import PlutusLedgerApi.V1.Value (AssetClass (..))
import PlutusTx qualified
@ -239,25 +240,24 @@ getNextProposalId (ProposalId pid) = ProposalId $ pid + 1
@since 0.1.0
-}
governorDatumValid :: Term s (PGovernorDatum :--> PBool)
governorDatumValid = phoistAcyclic $
pisGovernorDatumValid :: Term s (PGovernorDatum :--> PBool)
pisGovernorDatumValid = phoistAcyclic $
plam $ \datum -> unTermCont $ do
thresholds <-
pletFieldsC @'["execute", "create", "vote"] $
pfield @"proposalThresholds" # datum
PDiscrete execute' <- pmatchC thresholds.execute
PDiscrete draft' <- pmatchC thresholds.create
PDiscrete vote' <- pmatchC thresholds.vote
execute <- pletC $ pextract # execute'
draft <- pletC $ pextract # draft'
vote <- pletC $ pextract # vote'
datumF <-
pletFieldsC
@'[ "proposalThresholds"
, "proposalTimings"
, "createProposalTimeRangeMaxWidth"
]
datum
pure $
foldr1
(#&&)
[ ptraceIfFalse "Execute threshold is less than or equal to" $ 0 #<= execute
, ptraceIfFalse "Draft threshold is less than or equal to " $ 0 #<= draft
, ptraceIfFalse "Vote threshold is less than or equal to " $ 0 #<= vote
[ ptraceIfFalse "thersholds valid" $
pisProposalThresholdsValid # datumF.proposalThresholds
, ptraceIfFalse "timings valid" $
pisProposalTimeingConfigValid # datumF.proposalTimings
, ptraceIfFalse "time range valid" $
pisMaxTimeRangeWidthValid # datumF.createProposalTimeRangeMaxWidth
]

View file

@ -41,8 +41,8 @@ import Agora.Governor (
Governor (gstOutRef, gtClassRef, maximumCosigners),
GovernorRedeemer (..),
PGovernorDatum (PGovernorDatum),
governorDatumValid,
pgetNextProposalId,
pisGovernorDatumValid,
)
import Agora.Proposal (
PProposalDatum (..),
@ -180,7 +180,9 @@ governorPolicy gov =
let datumHash = pfield @"datumHash" # pfromData govOutput
datum = mustFindDatum' @PGovernorDatum # datumHash # txInfoF.datums
pure $ popaque $ governorDatumValid # datum
pguardC "Governor output datum valid" $ pisGovernorDatumValid # datum
pure $ popaque $ pconstant ()
{- | Validator for Governors.
@ -310,7 +312,8 @@ governorValidator gov =
pfromData $
mustBePJust # "Ouput governor state datum not found"
#$ ptryFindDatum # outputGovernorStateDatumHash # txInfoF.datums
pguardC "New datum is not valid" $ governorDatumValid # newGovernorDatum
pguardC "New datum is valid" $ pisGovernorDatumValid # newGovernorDatum
pure $
pmatchEnumFromData redeemer' $ \case

View file

@ -36,6 +36,7 @@ module Agora.Proposal (
pwinner',
pneutralOption,
pretractVotes,
pisProposalThresholdsValid,
) where
import Agora.Proposal.Time (PProposalStartingTime, PProposalTimingConfig, ProposalStartingTime, ProposalTimingConfig)
@ -53,6 +54,8 @@ import Plutarch.Api.V1 (
)
import Plutarch.Api.V1.AssocMap qualified as PAssocMap
import Plutarch.DataRepr (DerivePConstantViaData (..), PDataFields, PIsDataReprInstances (..))
import Plutarch.Extra.Comonad (pextract)
import Plutarch.Extra.Field (pletAllC)
import Plutarch.Extra.IsData (
DerivePConstantViaDataList (..),
DerivePConstantViaEnum (..),
@ -62,13 +65,13 @@ import Plutarch.Extra.IsData (
import Plutarch.Extra.Map qualified as PM
import Plutarch.Extra.Map.Unsorted qualified as PUM
import Plutarch.Extra.Other (DerivePNewtype' (..))
import Plutarch.Extra.TermCont (pguardC, pletC)
import Plutarch.Extra.TermCont (pguardC, pletC, pmatchC)
import Plutarch.Lift (
DerivePConstantViaNewtype (..),
PConstantDecl,
PUnsafeLiftDecl (..),
)
import Plutarch.SafeMoney (PDiscrete)
import Plutarch.SafeMoney (PDiscrete (..))
import Plutarch.Show (PShow (..))
import PlutusLedgerApi.V1 (DatumHash, PubKeyHash, ValidatorHash)
import PlutusLedgerApi.V1.Value (AssetClass)
@ -568,27 +571,6 @@ deriving via
instance
PTryFrom PData (PAsData PProposalVotes)
{- | Retract votes given the option and the amount of votes.
@since 0.1.0
-}
pretractVotes :: Term s (PResultTag :--> PInteger :--> PProposalVotes :--> PProposalVotes)
pretractVotes = phoistAcyclic $
plam $ \rt count votes ->
let voteMap :: Term _ (PMap 'Unsorted PResultTag PInteger)
voteMap = pto votes
in pcon $
PProposalVotes $
PM.pupdate
# plam
( \oldCount -> unTermCont $ do
newCount <- pletC $ oldCount - count
pguardC "Resulting vote count greater or equal to 0" $ 0 #<= newCount
pure $ pcon $ PJust newCount
)
# rt
# voteMap
-- | @since 0.1.0
instance PUnsafeLiftDecl PProposalVotes where type PLifted PProposalVotes = ProposalVotes
@ -864,3 +846,49 @@ pneutralOption = phoistAcyclic $
el' = pto el
in pnull # el'
in pfromData $ pfstBuiltin #$ mustBePJust # "No neutral option" #$ pfind # f # l
{- | Return true if the thresholds are valid.
@since 0.2.0
-}
pisProposalThresholdsValid :: forall (s :: S). Term s (PProposalThresholds :--> PBool)
pisProposalThresholdsValid = phoistAcyclic $
plam $ \thresholds -> unTermCont $ do
thresholdsF <- pletAllC thresholds
PDiscrete execute' <- pmatchC thresholdsF.execute
PDiscrete draft' <- pmatchC thresholdsF.create
PDiscrete vote' <- pmatchC thresholdsF.vote
execute <- pletC $ pextract # execute'
draft <- pletC $ pextract # draft'
vote <- pletC $ pextract # vote'
pure $
foldr1
(#&&)
[ ptraceIfFalse "Execute threshold is less than or equal to 0" $ 0 #<= execute
, ptraceIfFalse "Draft threshold is less than or equal to 0" $ 0 #<= draft
, ptraceIfFalse "Vote threshold is less than or equal to 0" $ 0 #<= vote
]
{- | Retract votes given the option and the amount of votes.
@since 0.1.0
-}
pretractVotes :: Term s (PResultTag :--> PInteger :--> PProposalVotes :--> PProposalVotes)
pretractVotes = phoistAcyclic $
plam $ \rt count votes ->
let voteMap :: Term _ (PMap 'Unsorted PResultTag PInteger)
voteMap = pto votes
in pcon $
PProposalVotes $
PM.pupdate
# plam
( \oldCount -> unTermCont $ do
newCount <- pletC $ oldCount - count
pguardC "Resulting vote count greater or equal to 0" $ 0 #<= newCount
pure $ pcon $ PJust newCount
)
# rt
# voteMap

View file

@ -26,6 +26,8 @@ module Agora.Proposal.Time (
isVotingPeriod,
isLockingPeriod,
isExecutionPeriod,
pisProposalTimeingConfigValid,
pisMaxTimeRangeWidthValid,
) where
import Agora.Plutarch.Orphans ()
@ -44,6 +46,7 @@ import Plutarch.DataRepr (
PDataFields,
PIsDataReprInstances (..),
)
import Plutarch.Extra.Field (pletAllC)
import Plutarch.Extra.TermCont (pguardC, pletFieldsC, pmatchC)
import Plutarch.Lift (
DerivePConstantViaNewtype (..),
@ -273,6 +276,43 @@ deriving via
--------------------------------------------------------------------------------
{- | Return true if the timing configuration is valid.
@since 0.2.0
-}
pisProposalTimeingConfigValid :: Term s (PProposalTimingConfig :--> PBool)
pisProposalTimeingConfigValid = phoistAcyclic $
plam $ \conf -> unTermCont $ do
confF <- pletAllC conf
-- everything is greater or equal 0
pure $
ptraceIfFalse "ge 0" $
foldr
( \t ->
(#&&)
( pconstant 0
#<= pfromData t
)
)
(pconstant True)
[ confF.draftTime
, confF.votingTime
, confF.lockingTime
, confF.executingTime
]
{- | Return true if the maximum time width is greater than 0.
@since 0.2.0
-}
pisMaxTimeRangeWidthValid :: Term s (PMaxTimeRangeWidth :--> PBool)
pisMaxTimeRangeWidthValid =
phoistAcyclic $
plam $
ptraceIfFalse "greater than 0"
. (pconstant (MaxTimeRangeWidth 0) #<)
{- | Get the starting time of a proposal, from the 'PlutusLedgerApi.V1.txInfoValidPeriod' field.
For every proposal, this is only meant to run once upon creation. Given time range should be
tight enough, meaning that the width of the time range should be less than the maximum value.