461 lines
19 KiB
Haskell
461 lines
19 KiB
Haskell
{- |
|
|
Module : Spec.Proposal
|
|
Maintainer : emi@haskell.fyi
|
|
Description: Tests for Proposal policy and validator
|
|
|
|
Tests for Proposal policy and validator
|
|
-}
|
|
module Spec.Proposal (specs) where
|
|
|
|
import Sample.Proposal.Advance qualified as Advance
|
|
import Sample.Proposal.Cosign qualified as Cosign
|
|
import Sample.Proposal.Create qualified as Create
|
|
import Sample.Proposal.PrivilegeEscalate qualified as PrivilegeEscalate
|
|
import Sample.Proposal.Unlock qualified as Unlock
|
|
import Sample.Proposal.Vote qualified as Vote
|
|
|
|
import Test.Specification (
|
|
SpecificationTree,
|
|
group,
|
|
)
|
|
|
|
-- | Stake specs.
|
|
specs :: [SpecificationTree]
|
|
specs =
|
|
[ group
|
|
"policy (proposal creation)"
|
|
[ Create.mkTestTree
|
|
"legal"
|
|
Create.totallyValidParameters
|
|
True
|
|
True
|
|
True
|
|
, group
|
|
"illegal"
|
|
[ Create.mkTestTree
|
|
"invalid next proposal id"
|
|
Create.invalidOutputGovernorDatumParameters
|
|
True
|
|
False
|
|
True
|
|
, Create.mkTestTree
|
|
"use other's stake"
|
|
Create.useStakeOwnBySomeoneElseParameters
|
|
True
|
|
True
|
|
False
|
|
, Create.mkTestTree
|
|
"altered stake"
|
|
Create.invalidOutputStakeParameters
|
|
True
|
|
False
|
|
False
|
|
, Create.mkTestTree
|
|
"invalid stake locks"
|
|
Create.addInvalidLocksParameters
|
|
True
|
|
True
|
|
False
|
|
, Create.mkTestTree
|
|
"has reached maximum proposals limit"
|
|
Create.exceedMaximumProposalsParameters
|
|
True
|
|
False
|
|
True
|
|
, Create.mkTestTree
|
|
"loose time range"
|
|
Create.timeRangeNotTightParameters
|
|
True
|
|
False
|
|
True
|
|
, Create.mkTestTree
|
|
"open time range"
|
|
Create.timeRangeNotClosedParameters
|
|
True
|
|
False
|
|
True
|
|
, group "invalid proposal status" $
|
|
map
|
|
( \ps ->
|
|
Create.mkTestTree
|
|
(show ps.proposalStatus)
|
|
ps
|
|
True
|
|
False
|
|
True
|
|
)
|
|
Create.invalidProposalStatusParameters
|
|
, Create.mkTestTree
|
|
"fake SST"
|
|
Create.fakeSSTParameters
|
|
True
|
|
False
|
|
False
|
|
, Create.mkTestTree
|
|
"wrong governor redeemer"
|
|
Create.wrongGovernorRedeemer
|
|
False
|
|
False
|
|
True
|
|
, Create.mkTestTree
|
|
"wrong governor redeemer"
|
|
Create.wrongGovernorRedeemer1
|
|
False
|
|
False
|
|
True
|
|
]
|
|
]
|
|
, group
|
|
"validator"
|
|
[ group
|
|
"cosignature"
|
|
[ Cosign.mkTestTree
|
|
"legal"
|
|
Cosign.totallyValid
|
|
(Cosign.Validity True True)
|
|
, group
|
|
"illegal"
|
|
[ Cosign.mkTestTree
|
|
"insufficient staked amount"
|
|
Cosign.insufficientStakedAmount
|
|
(Cosign.Validity False True)
|
|
, Cosign.mkTestTree
|
|
"proposal locks not updated"
|
|
Cosign.locksNotUpdated
|
|
(Cosign.Validity True False)
|
|
, Cosign.mkTestTree
|
|
"duplicate cosigners"
|
|
Cosign.duplicateCosigners
|
|
(Cosign.Validity False True)
|
|
, Cosign.mkTestTree
|
|
"cosigners not updated"
|
|
Cosign.cosignersNotUpdated
|
|
(Cosign.Validity False True)
|
|
, group "cosign after draft" $
|
|
map
|
|
( \b ->
|
|
Cosign.mkTestTree
|
|
"(negative test)"
|
|
b
|
|
(Cosign.Validity False True)
|
|
)
|
|
Cosign.cosignAfterDraft
|
|
]
|
|
]
|
|
, group
|
|
"voting"
|
|
[ group
|
|
"legal"
|
|
[ group "different number of stakes" $
|
|
map
|
|
( \s ->
|
|
group
|
|
(unwords [show s, "stakes"])
|
|
[ Vote.mkTestTree
|
|
"by owner"
|
|
(Vote.mkValidOwnerVoteBundle s)
|
|
(Vote.Validity True True)
|
|
, Vote.mkTestTree
|
|
"by delegatee"
|
|
(Vote.mkValidDelegateeVoteBundle s)
|
|
(Vote.Validity True True)
|
|
]
|
|
)
|
|
[1, 3, 5, 7, 9]
|
|
, Vote.mkTestTree
|
|
"transparent non-GT tokens"
|
|
Vote.transparentAssets
|
|
(Vote.Validity True True)
|
|
, Vote.mkTestTree
|
|
"Delegatee vote with own and delegated stakes in one tx"
|
|
Vote.delegateeVoteWithOwnAndDelegatedStakeBundle
|
|
(Vote.Validity True True)
|
|
]
|
|
, group
|
|
"illegal"
|
|
[ Vote.mkTestTree
|
|
"vote for nonexistent outcome"
|
|
Vote.voteForNonexistentOutcome
|
|
(Vote.Validity False True)
|
|
, Vote.mkTestTree
|
|
"unauthorized tx"
|
|
Vote.transactionNotAuthorized
|
|
(Vote.Validity True False)
|
|
, Vote.mkTestTree
|
|
"no proposal"
|
|
Vote.noProposal
|
|
(Vote.Validity False False)
|
|
, Vote.mkTestTree
|
|
"more than one proposals"
|
|
Vote.voteForNonexistentOutcome
|
|
(Vote.Validity False True)
|
|
, Vote.mkTestTree
|
|
"locks not added"
|
|
Vote.invalidLocks
|
|
(Vote.Validity True False)
|
|
, Vote.mkTestTree
|
|
"attempt to burn stakes"
|
|
Vote.destroyStakes
|
|
(Vote.Validity True False)
|
|
, Vote.mkTestTree
|
|
"insufficient staked amount"
|
|
Vote.insufficientAmount
|
|
(Vote.Validity False True)
|
|
, Vote.mkTestTree
|
|
"insufficient staked amount"
|
|
Vote.insufficientAmount1
|
|
(Vote.Validity False True)
|
|
]
|
|
]
|
|
, group
|
|
"advancing"
|
|
$ let possibleCosigners = [1, 5, 10]
|
|
possibleEffects = [1, 2, 5]
|
|
in do
|
|
cs <- possibleCosigners
|
|
es <- possibleEffects
|
|
|
|
let groupName =
|
|
unwords
|
|
[ "with"
|
|
, show cs
|
|
, "cosigners"
|
|
, "and"
|
|
, show es
|
|
, "effects"
|
|
]
|
|
|
|
pure $
|
|
group
|
|
groupName
|
|
[ group
|
|
"legal"
|
|
$ let allValid =
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just True
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
mkName b =
|
|
unwords
|
|
[ "from"
|
|
, show b.proposalParameters.fromStatus
|
|
, "to"
|
|
, show b.proposalParameters.toStatus
|
|
]
|
|
in [ Advance.mkTestTree'
|
|
"to next state"
|
|
mkName
|
|
(Advance.mkValidToNextStateBundles cs es)
|
|
allValid
|
|
, Advance.mkTestTree'
|
|
"to failed state"
|
|
mkName
|
|
(Advance.mkValidToFailedStateBundles cs es)
|
|
allValid
|
|
]
|
|
, group
|
|
"illegal"
|
|
[ Advance.mkTestTree'
|
|
"advance finished proposals"
|
|
(const "(negative test)")
|
|
(Advance.mkFromFinishedBundles cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"insufficient cosigns"
|
|
(Advance.mkInsufficientCosignsBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Nothing
|
|
, forAuthorityTokenPolicy = Nothing
|
|
}
|
|
, Advance.mkTestTree
|
|
"insufficient votes"
|
|
(Advance.mkInsufficientVotesBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Nothing
|
|
, forAuthorityTokenPolicy = Nothing
|
|
}
|
|
, Advance.mkTestTree
|
|
"ambiguous winning effect"
|
|
(Advance.mkAmbiguousWinnerBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Nothing
|
|
, forAuthorityTokenPolicy = Nothing
|
|
}
|
|
, Advance.mkTestTree'
|
|
"to next state too late"
|
|
(\b -> unwords ["from", show b.proposalParameters.fromStatus])
|
|
(Advance.mkToNextStateTooLateBundles cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just True
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"forget to mint GATs"
|
|
(Advance.mkNoGATMintedBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Nothing
|
|
}
|
|
, Advance.mkTestTree
|
|
"mint GATs for wrong validators"
|
|
(Advance.mkMintGATsForWrongEffectsBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"mint GATs with bad token name"
|
|
(Advance.mkMintGATsWithoutTagBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"wrong GAT datum"
|
|
(Advance.mkGATsWithWrongDatumBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"invalid governor output datum"
|
|
(Advance.mkBadGovernorOutputDatumBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree'
|
|
"fastforward to finished"
|
|
(\b -> unwords ["from", show b.proposalParameters.fromStatus])
|
|
(Advance.mkFastforwardToFinishBundles cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = False
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just True
|
|
}
|
|
, Advance.mkTestTree
|
|
"wrong governor redeemer"
|
|
(Advance.mkBadGovernorRedeemerBundle cs es)
|
|
Advance.Validity
|
|
{ forProposalValidator = True
|
|
, forStakeValidator = True
|
|
, forGovernorValidator = Just False
|
|
, forAuthorityTokenPolicy = Just False
|
|
}
|
|
]
|
|
]
|
|
, group "unlocking" $
|
|
let stakeCountCases = [1, 3, 5, 7, 9, 11]
|
|
|
|
mkSubgroupName nStakes = unwords ["with", show nStakes, "stakes"]
|
|
|
|
mkLegalGroup nStakes =
|
|
group
|
|
(mkSubgroupName nStakes)
|
|
[ Unlock.mkTestTree
|
|
"voter: retract votes while voting"
|
|
(Unlock.mkValidVoterRetractVotes nStakes)
|
|
(Unlock.Validity True True)
|
|
, Unlock.mkTestTree
|
|
"voter: retract votes while voting by delegatee"
|
|
(Unlock.mkValidDelegateeRetractVotes nStakes)
|
|
(Unlock.Validity True True)
|
|
, Unlock.mkTestTree
|
|
"voter/creator: retract votes while voting"
|
|
(Unlock.mkValidVoterCreatorRetractVotes nStakes)
|
|
(Unlock.Validity True True)
|
|
, Unlock.mkTestTree
|
|
"creator: remove creator lock after voting"
|
|
(Unlock.mkValidCreatorRemoveLock nStakes)
|
|
(Unlock.Validity True True)
|
|
, Unlock.mkTestTree
|
|
"Voter: remove lock after voting"
|
|
(Unlock.mkValidVoterRemoveLockAfterVoting nStakes)
|
|
(Unlock.Validity True True)
|
|
]
|
|
|
|
mkIllegalGroup nStakes =
|
|
group
|
|
(mkSubgroupName nStakes)
|
|
[ group "retract votes while not voting" $
|
|
map
|
|
( \c ->
|
|
Unlock.mkTestTree
|
|
"(negative test)"
|
|
c
|
|
(Unlock.Validity False True)
|
|
)
|
|
(Unlock.mkRetractVotesWhileNotVoting nStakes)
|
|
, group "remove creator too early" $
|
|
map
|
|
( \c ->
|
|
Unlock.mkTestTree
|
|
"(negative test)"
|
|
c
|
|
(Unlock.Validity True False)
|
|
)
|
|
(Unlock.mkRemoveCreatorLockBeforeFinished nStakes)
|
|
, Unlock.mkTestTree
|
|
"unlock an irrelevant stake"
|
|
(Unlock.mkUnockIrrelevantStakes nStakes)
|
|
(Unlock.Validity False False)
|
|
, Unlock.mkTestTree
|
|
"creator: retract votes"
|
|
(Unlock.mkCreatorRetractVotes nStakes)
|
|
(Unlock.Validity False True)
|
|
, Unlock.mkTestTree
|
|
"change output stake value"
|
|
(Unlock.mkChangeOutputStakeValue nStakes)
|
|
(Unlock.Validity True False)
|
|
, Unlock.mkTestTree
|
|
"use fake stake"
|
|
(Unlock.mkUseFakeStakes nStakes)
|
|
(Unlock.Validity False False)
|
|
, Unlock.mkTestTree
|
|
"retract votes in cooldown"
|
|
(Unlock.mkDisrespectCooldown nStakes)
|
|
(Unlock.Validity True False)
|
|
]
|
|
|
|
legalGroup = group "legal" $ map mkLegalGroup stakeCountCases
|
|
illegalGroup = group "illegal" $ map mkIllegalGroup stakeCountCases
|
|
in [legalGroup, illegalGroup]
|
|
]
|
|
, group
|
|
"privilege escalate"
|
|
[ PrivilegeEscalate.mkTestTree
|
|
"vote"
|
|
PrivilegeEscalate.Voting
|
|
(PrivilegeEscalate.Validity False False)
|
|
, PrivilegeEscalate.mkTestTree
|
|
"retract votes"
|
|
PrivilegeEscalate.RetractingVotes
|
|
(PrivilegeEscalate.Validity False False)
|
|
]
|
|
]
|