fix tests for cosigning
This commit is contained in:
parent
c65bf3e6d2
commit
e762db8d18
7 changed files with 320 additions and 194 deletions
|
|
@ -18,7 +18,7 @@ import Agora.Proposal.Time (
|
||||||
ProposalTimingConfig (ProposalTimingConfig),
|
ProposalTimingConfig (ProposalTimingConfig),
|
||||||
)
|
)
|
||||||
import Data.Default.Class (Default (def))
|
import Data.Default.Class (Default (def))
|
||||||
import Data.Tagged (Tagged (Tagged), untag)
|
import Data.Tagged (Tagged (Tagged))
|
||||||
import Data.Universe (Finite (..), Universe (..))
|
import Data.Universe (Finite (..), Universe (..))
|
||||||
import Plutarch.Api.V2 (PScriptContext)
|
import Plutarch.Api.V2 (PScriptContext)
|
||||||
import Plutarch.Builtin (pforgetData)
|
import Plutarch.Builtin (pforgetData)
|
||||||
|
|
@ -65,6 +65,7 @@ data GovernorDatumCases
|
||||||
| CreateLE0
|
| CreateLE0
|
||||||
| ToVotingLE0
|
| ToVotingLE0
|
||||||
| VoteLE0
|
| VoteLE0
|
||||||
|
| CosignLE0
|
||||||
| Correct
|
| Correct
|
||||||
deriving stock (Eq, Show)
|
deriving stock (Eq, Show)
|
||||||
|
|
||||||
|
|
@ -73,6 +74,7 @@ instance Universe GovernorDatumCases where
|
||||||
[ ExecuteLE0
|
[ ExecuteLE0
|
||||||
, CreateLE0
|
, CreateLE0
|
||||||
, VoteLE0
|
, VoteLE0
|
||||||
|
, CosignLE0
|
||||||
, Correct
|
, Correct
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -89,11 +91,12 @@ governorDatumValidProperty =
|
||||||
classifiedPropertyNative gen (const []) expected classifier pisGovernorDatumValid
|
classifiedPropertyNative gen (const []) expected classifier pisGovernorDatumValid
|
||||||
where
|
where
|
||||||
classifier :: GovernorDatum -> GovernorDatumCases
|
classifier :: GovernorDatum -> GovernorDatumCases
|
||||||
classifier ((.proposalThresholds) -> ProposalThresholds e c tv v)
|
classifier ((.proposalThresholds) -> ProposalThresholds e c tv v co)
|
||||||
| e < 0 = ExecuteLE0
|
| e < 0 = ExecuteLE0
|
||||||
| c < 0 = CreateLE0
|
| c < 0 = CreateLE0
|
||||||
| tv < 0 = ToVotingLE0
|
| tv < 0 = ToVotingLE0
|
||||||
| v < 0 = VoteLE0
|
| v < 0 = VoteLE0
|
||||||
|
| co < 0 = CosignLE0
|
||||||
| otherwise = Correct
|
| otherwise = Correct
|
||||||
|
|
||||||
expected :: GovernorDatum -> Maybe Bool
|
expected :: GovernorDatum -> Maybe Bool
|
||||||
|
|
@ -114,25 +117,25 @@ governorDatumValidProperty =
|
||||||
create <- validGT
|
create <- validGT
|
||||||
toVoting <- validGT
|
toVoting <- validGT
|
||||||
vote <- validGT
|
vote <- validGT
|
||||||
|
cosign <- validGT
|
||||||
le0 <- taggedInteger (-1000, -1)
|
le0 <- taggedInteger (-1000, -1)
|
||||||
|
|
||||||
case c of
|
case c of
|
||||||
ExecuteLE0 ->
|
ExecuteLE0 ->
|
||||||
-- execute < 0
|
-- execute < 0
|
||||||
return $ ProposalThresholds le0 create toVoting vote
|
return $ ProposalThresholds le0 create toVoting vote cosign
|
||||||
CreateLE0 ->
|
CreateLE0 ->
|
||||||
-- c < 0
|
-- c < 0
|
||||||
return $ ProposalThresholds execute le0 toVoting vote
|
return $ ProposalThresholds execute le0 toVoting vote cosign
|
||||||
ToVotingLE0 ->
|
ToVotingLE0 ->
|
||||||
return $ ProposalThresholds execute create le0 vote
|
return $ ProposalThresholds execute create le0 vote cosign
|
||||||
VoteLE0 ->
|
VoteLE0 ->
|
||||||
-- vote < 0
|
-- vote < 0
|
||||||
return $ ProposalThresholds execute create toVoting le0
|
return $ ProposalThresholds execute create toVoting le0 cosign
|
||||||
Correct -> do
|
CosignLE0 ->
|
||||||
-- c <= vote < execute
|
return $ ProposalThresholds execute create toVoting vote le0
|
||||||
nv <- taggedInteger (0, untag execute - 1)
|
Correct ->
|
||||||
nc <- taggedInteger (0, untag nv)
|
return $ ProposalThresholds execute create toVoting vote cosign
|
||||||
return $ ProposalThresholds execute nc toVoting nv
|
|
||||||
|
|
||||||
data GovernorPolicyCases
|
data GovernorPolicyCases
|
||||||
= ReferenceUTXONotSpent
|
= ReferenceUTXONotSpent
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ validGovernorOutputDatum =
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidProposalThresholds :: ProposalThresholds
|
invalidProposalThresholds :: ProposalThresholds
|
||||||
invalidProposalThresholds = ProposalThresholds (-1) (-1) (-1) (-1)
|
invalidProposalThresholds = ProposalThresholds (-1) (-1) (-1) (-1) (-1)
|
||||||
|
|
||||||
invalidMaxTimeRangeWidth :: MaxTimeRangeWidth
|
invalidMaxTimeRangeWidth :: MaxTimeRangeWidth
|
||||||
invalidMaxTimeRangeWidth = MaxTimeRangeWidth 0
|
invalidMaxTimeRangeWidth = MaxTimeRangeWidth 0
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ mkGovernorOutputDatum ValueInvalid =
|
||||||
, create = -1
|
, create = -1
|
||||||
, toVoting = -1
|
, toVoting = -1
|
||||||
, vote = -1
|
, vote = -1
|
||||||
|
, cosign = -1
|
||||||
}
|
}
|
||||||
in Just $
|
in Just $
|
||||||
toData $
|
toData $
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,22 @@ Description: Generate sample data for testing the functionalities of cosigning p
|
||||||
Sample and utilities for testing the functionalities of cosigning proposals.
|
Sample and utilities for testing the functionalities of cosigning proposals.
|
||||||
-}
|
-}
|
||||||
module Sample.Proposal.Cosign (
|
module Sample.Proposal.Cosign (
|
||||||
Parameters (..),
|
StakedAmount (..),
|
||||||
validCosignNParameters,
|
StakeOwner (..),
|
||||||
duplicateCosignersParameters,
|
StakeParameters (..),
|
||||||
statusNotDraftCosignNParameters,
|
SignedBy (..),
|
||||||
|
TransactionParameters (..),
|
||||||
|
ProposalParameters (..),
|
||||||
|
ParameterBundle (..),
|
||||||
|
Validity (..),
|
||||||
|
cosign,
|
||||||
mkTestTree,
|
mkTestTree,
|
||||||
|
totallyValid,
|
||||||
|
insufficientStakedAmount,
|
||||||
|
duplicateCosigners,
|
||||||
|
locksNotUpdated,
|
||||||
|
cosignersNotUpdated,
|
||||||
|
cosignAfterDraft,
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Agora.Governor (Governor (..))
|
import Agora.Governor (Governor (..))
|
||||||
|
|
@ -19,6 +30,7 @@ import Agora.Proposal (
|
||||||
ProposalId (ProposalId),
|
ProposalId (ProposalId),
|
||||||
ProposalRedeemer (Cosign),
|
ProposalRedeemer (Cosign),
|
||||||
ProposalStatus (..),
|
ProposalStatus (..),
|
||||||
|
ProposalThresholds (..),
|
||||||
ResultTag (ResultTag),
|
ResultTag (ResultTag),
|
||||||
emptyVotesFor,
|
emptyVotesFor,
|
||||||
)
|
)
|
||||||
|
|
@ -29,7 +41,9 @@ import Agora.Proposal.Time (
|
||||||
import Agora.SafeMoney (GTTag)
|
import Agora.SafeMoney (GTTag)
|
||||||
import Agora.Scripts (AgoraScripts (..))
|
import Agora.Scripts (AgoraScripts (..))
|
||||||
import Agora.Stake (
|
import Agora.Stake (
|
||||||
StakeDatum (StakeDatum, owner),
|
ProposalLock (Cosigned, Created),
|
||||||
|
StakeDatum (..),
|
||||||
|
StakeRedeemer (PermitVote),
|
||||||
)
|
)
|
||||||
import Data.Coerce (coerce)
|
import Data.Coerce (coerce)
|
||||||
import Data.Default (def)
|
import Data.Default (def)
|
||||||
|
|
@ -38,25 +52,25 @@ import Data.Map.Strict qualified as StrictMap
|
||||||
import Data.Tagged (untag)
|
import Data.Tagged (untag)
|
||||||
import Plutarch.Context (
|
import Plutarch.Context (
|
||||||
input,
|
input,
|
||||||
|
normalizeValue,
|
||||||
output,
|
output,
|
||||||
referenceInput,
|
|
||||||
script,
|
script,
|
||||||
signedWith,
|
signedWith,
|
||||||
timeRange,
|
timeRange,
|
||||||
txId,
|
txId,
|
||||||
withDatum,
|
withDatum,
|
||||||
withInlineDatum,
|
withInlineDatum,
|
||||||
|
withRedeemer,
|
||||||
withRef,
|
withRef,
|
||||||
withValue,
|
withValue,
|
||||||
)
|
)
|
||||||
import Plutarch.SafeMoney (Discrete)
|
import Plutarch.SafeMoney (Discrete (Discrete))
|
||||||
import PlutusLedgerApi.V1.Value qualified as Value
|
import PlutusLedgerApi.V1.Value qualified as Value
|
||||||
import PlutusLedgerApi.V2 (
|
import PlutusLedgerApi.V2 (
|
||||||
Credential (PubKeyCredential),
|
Credential (PubKeyCredential),
|
||||||
POSIXTimeRange,
|
POSIXTime (POSIXTime),
|
||||||
PubKeyHash,
|
PubKeyHash,
|
||||||
TxOutRef (..),
|
TxOutRef (TxOutRef),
|
||||||
Value,
|
|
||||||
)
|
)
|
||||||
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
|
import Sample.Proposal.Shared (proposalTxRef, stakeTxRef)
|
||||||
import Sample.Shared (
|
import Sample.Shared (
|
||||||
|
|
@ -66,36 +80,81 @@ import Sample.Shared (
|
||||||
minAda,
|
minAda,
|
||||||
proposalPolicySymbol,
|
proposalPolicySymbol,
|
||||||
proposalValidatorHash,
|
proposalValidatorHash,
|
||||||
signer,
|
|
||||||
stakeAssetClass,
|
stakeAssetClass,
|
||||||
stakeValidatorHash,
|
stakeValidatorHash,
|
||||||
)
|
)
|
||||||
import Test.Specification (
|
import Test.Specification (
|
||||||
SpecificationTree,
|
SpecificationTree,
|
||||||
|
group,
|
||||||
testValidator,
|
testValidator,
|
||||||
)
|
)
|
||||||
import Test.Util (CombinableBuilder, closedBoundedInterval, mkSpending, pubKeyHashes, sortValue)
|
import Test.Util (
|
||||||
|
CombinableBuilder,
|
||||||
|
closedBoundedInterval,
|
||||||
|
mkSpending,
|
||||||
|
pubKeyHashes,
|
||||||
|
)
|
||||||
|
|
||||||
-- | Parameters for cosigning a proposal.
|
data StakedAmount = Sufficient | Insufficient
|
||||||
data Parameters = Parameters
|
|
||||||
{ newCosigners :: [Credential]
|
data StakeOwner = Creator | Other
|
||||||
-- ^ New cosigners to be added, and the owners of the generated stakes.
|
|
||||||
, proposalStatus :: ProposalStatus
|
data StakeParameters = StakeParameters
|
||||||
-- ^ Current state of the proposal.
|
{ gtAmount :: StakedAmount
|
||||||
|
, stakeOwner :: StakeOwner
|
||||||
|
, dontUpdateLocks :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Owner of the creator stake, doesn't really matter in this case.
|
data SignedBy = Owner | Delegatee | Unknown
|
||||||
proposalCreator :: PubKeyHash
|
|
||||||
proposalCreator = signer
|
|
||||||
|
|
||||||
-- | The amount of GTs every generated stake has, doesn't really matter in this case.
|
newtype TransactionParameters = TransactionParameters
|
||||||
perStakedGTs :: Discrete GTTag
|
{ signedBy :: SignedBy
|
||||||
perStakedGTs = 5
|
}
|
||||||
|
|
||||||
{- | Create input proposal datum given the parameters.
|
data ProposalParameters = ProposalParameters
|
||||||
In particular, 'status' is set to 'proposalStstus'.
|
{ proposalStatus :: ProposalStatus
|
||||||
-}
|
, dontUpdateCosigners :: Bool
|
||||||
mkProposalInputDatum :: Parameters -> ProposalDatum
|
}
|
||||||
|
|
||||||
|
-- | Parameters for cosigning a proposal.
|
||||||
|
data ParameterBundle = ParameterBundle
|
||||||
|
{ stakeParameters :: StakeParameters
|
||||||
|
, proposalParameters :: ProposalParameters
|
||||||
|
, transactionParameters :: TransactionParameters
|
||||||
|
}
|
||||||
|
|
||||||
|
data Validity = Validity
|
||||||
|
{ forProposalValidator :: Bool
|
||||||
|
, forStakeValidator :: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mkStakeAmount :: StakedAmount -> Discrete GTTag
|
||||||
|
mkStakeAmount Sufficient = Discrete $ (def @ProposalThresholds).cosign
|
||||||
|
mkStakeAmount Insufficient = mkStakeAmount Sufficient - 1
|
||||||
|
|
||||||
|
mkStakeOwner :: StakeOwner -> PubKeyHash
|
||||||
|
mkStakeOwner Creator = creator
|
||||||
|
mkStakeOwner Other = pubKeyHashes !! 2
|
||||||
|
|
||||||
|
mkSigner :: StakeOwner -> SignedBy -> PubKeyHash
|
||||||
|
mkSigner so Owner = mkStakeOwner so
|
||||||
|
mkSigner _ Delegatee = delegatee
|
||||||
|
mkSigner _ Unknown = pubKeyHashes !! 4
|
||||||
|
|
||||||
|
creator :: PubKeyHash
|
||||||
|
creator = pubKeyHashes !! 1
|
||||||
|
|
||||||
|
delegatee :: PubKeyHash
|
||||||
|
delegatee = pubKeyHashes !! 3
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
defProposalId :: ProposalId
|
||||||
|
defProposalId = ProposalId 0
|
||||||
|
|
||||||
|
mkProposalInputDatum :: ParameterBundle -> ProposalDatum
|
||||||
mkProposalInputDatum ps =
|
mkProposalInputDatum ps =
|
||||||
let effects =
|
let effects =
|
||||||
StrictMap.fromList
|
StrictMap.fromList
|
||||||
|
|
@ -105,98 +164,136 @@ mkProposalInputDatum ps =
|
||||||
in ProposalDatum
|
in ProposalDatum
|
||||||
{ proposalId = ProposalId 0
|
{ proposalId = ProposalId 0
|
||||||
, effects = effects
|
, effects = effects
|
||||||
, status = ps.proposalStatus
|
, status = ps.proposalParameters.proposalStatus
|
||||||
, cosigners = [PubKeyCredential proposalCreator]
|
, cosigners = [PubKeyCredential creator]
|
||||||
, thresholds = def
|
, thresholds = def
|
||||||
, votes = emptyVotesFor effects
|
, votes = emptyVotesFor effects
|
||||||
, timingConfig = def
|
, timingConfig = def
|
||||||
, startingTime = ProposalStartingTime 0
|
, startingTime = ProposalStartingTime 0
|
||||||
}
|
}
|
||||||
|
|
||||||
{- | Create the output proposal datum given the parameters.
|
mkProposalOutputDatum :: ParameterBundle -> ProposalDatum
|
||||||
The 'newCosigners' is added to the exisiting list of cosigners, note the said list should be sorted in
|
|
||||||
ascending order.
|
|
||||||
-}
|
|
||||||
mkProposalOutputDatum :: Parameters -> ProposalDatum
|
|
||||||
mkProposalOutputDatum ps =
|
mkProposalOutputDatum ps =
|
||||||
let inputDatum = mkProposalInputDatum ps
|
let inputDatum = mkProposalInputDatum ps
|
||||||
in inputDatum
|
stakeOwner =
|
||||||
{ cosigners = sort $ inputDatum.cosigners <> ps.newCosigners
|
PubKeyCredential $
|
||||||
|
mkStakeOwner ps.stakeParameters.stakeOwner
|
||||||
|
newCosigners =
|
||||||
|
if ps.proposalParameters.dontUpdateCosigners
|
||||||
|
then inputDatum.cosigners
|
||||||
|
else sort $ stakeOwner : inputDatum.cosigners
|
||||||
|
in inputDatum {cosigners = newCosigners}
|
||||||
|
|
||||||
|
proposalRedeemer :: ProposalRedeemer
|
||||||
|
proposalRedeemer = Cosign
|
||||||
|
|
||||||
|
proposalRef :: TxOutRef
|
||||||
|
proposalRef = TxOutRef proposalTxRef 1
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
mkStakeInputDatum :: ParameterBundle -> StakeDatum
|
||||||
|
mkStakeInputDatum ps =
|
||||||
|
let sps = ps.stakeParameters
|
||||||
|
amount = mkStakeAmount sps.gtAmount
|
||||||
|
owner = mkStakeOwner sps.stakeOwner
|
||||||
|
locks = case sps.stakeOwner of
|
||||||
|
Creator -> [Created defProposalId]
|
||||||
|
_ -> []
|
||||||
|
in StakeDatum
|
||||||
|
{ stakedAmount = amount
|
||||||
|
, owner = PubKeyCredential owner
|
||||||
|
, delegatedTo = Just $ PubKeyCredential delegatee
|
||||||
|
, lockedBy = locks
|
||||||
}
|
}
|
||||||
|
|
||||||
-- | Create all the input stakes given the parameters.
|
mkStakeOuputDatum :: ParameterBundle -> StakeDatum
|
||||||
mkStakeInputDatums :: Parameters -> [StakeDatum]
|
mkStakeOuputDatum ps =
|
||||||
mkStakeInputDatums =
|
let sps = ps.stakeParameters
|
||||||
fmap (\pk -> StakeDatum perStakedGTs pk Nothing [])
|
inpDatum = mkStakeInputDatum ps
|
||||||
. (.newCosigners)
|
locks =
|
||||||
|
if sps.dontUpdateLocks
|
||||||
|
then inpDatum.lockedBy
|
||||||
|
else Cosigned defProposalId : inpDatum.lockedBy
|
||||||
|
in inpDatum {lockedBy = locks}
|
||||||
|
|
||||||
|
stakeRedeemer :: StakeRedeemer
|
||||||
|
stakeRedeemer = PermitVote
|
||||||
|
|
||||||
|
stakeRef :: TxOutRef
|
||||||
|
stakeRef = TxOutRef stakeTxRef 0
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- | Create a 'TxInfo' that tries to cosign a proposal with new cosigners.
|
-- | Create a 'TxInfo' that tries to cosign a proposal with new cosigners.
|
||||||
cosign :: forall b. CombinableBuilder b => Parameters -> b
|
cosign :: forall b. CombinableBuilder b => ParameterBundle -> b
|
||||||
cosign ps = builder
|
cosign ps = builder
|
||||||
where
|
where
|
||||||
pst = Value.singleton proposalPolicySymbol "" 1
|
pst = Value.singleton proposalPolicySymbol "" 1
|
||||||
sst = Value.assetClassValue stakeAssetClass 1
|
sst = Value.assetClassValue stakeAssetClass 1
|
||||||
|
|
||||||
---
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
stakeInputDatums :: [StakeDatum]
|
stakeInputDatum = mkStakeInputDatum ps
|
||||||
stakeInputDatums = mkStakeInputDatums ps
|
stakeOutputDatum = mkStakeOuputDatum ps
|
||||||
|
|
||||||
stakeValue :: Value
|
|
||||||
stakeValue =
|
stakeValue =
|
||||||
sortValue $
|
normalizeValue $
|
||||||
minAda
|
minAda
|
||||||
<> Value.assetClassValue
|
<> Value.assetClassValue
|
||||||
(untag governor.gtClassRef)
|
(untag governor.gtClassRef)
|
||||||
(fromDiscrete perStakedGTs)
|
( fromDiscrete $
|
||||||
|
mkStakeAmount ps.stakeParameters.gtAmount
|
||||||
|
)
|
||||||
<> sst
|
<> sst
|
||||||
|
|
||||||
stakeBuilder =
|
stakeBuilder =
|
||||||
foldMap
|
|
||||||
( \(stakeDatum, refIdx) ->
|
|
||||||
mconcat
|
mconcat
|
||||||
[ referenceInput $
|
[ input $
|
||||||
mconcat
|
mconcat
|
||||||
[ script stakeValidatorHash
|
[ script stakeValidatorHash
|
||||||
, withValue stakeValue
|
, withValue stakeValue
|
||||||
, withInlineDatum stakeDatum
|
, withInlineDatum stakeInputDatum
|
||||||
, withRef (mkStakeRef refIdx)
|
, withRef stakeRef
|
||||||
|
, withRedeemer stakeRedeemer
|
||||||
|
]
|
||||||
|
, output $
|
||||||
|
mconcat
|
||||||
|
[ script stakeValidatorHash
|
||||||
|
, withValue stakeValue
|
||||||
|
, withInlineDatum stakeOutputDatum
|
||||||
]
|
]
|
||||||
, case stakeDatum.owner of
|
|
||||||
PubKeyCredential k -> signedWith k
|
|
||||||
_ -> mempty
|
|
||||||
]
|
]
|
||||||
)
|
|
||||||
$ zip
|
|
||||||
stakeInputDatums
|
|
||||||
[0 ..]
|
|
||||||
|
|
||||||
---
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
proposalInputDatum :: ProposalDatum
|
|
||||||
proposalInputDatum = mkProposalInputDatum ps
|
proposalInputDatum = mkProposalInputDatum ps
|
||||||
|
|
||||||
proposalOutputDatum :: ProposalDatum
|
|
||||||
proposalOutputDatum = mkProposalOutputDatum ps
|
proposalOutputDatum = mkProposalOutputDatum ps
|
||||||
|
|
||||||
|
proposalValue =
|
||||||
|
normalizeValue $
|
||||||
|
pst <> minAda
|
||||||
|
|
||||||
proposalBuilder =
|
proposalBuilder =
|
||||||
mconcat
|
mconcat
|
||||||
[ input $
|
[ input $
|
||||||
mconcat
|
mconcat
|
||||||
[ script proposalValidatorHash
|
[ script proposalValidatorHash
|
||||||
, withValue pst
|
, withValue proposalValue
|
||||||
, withDatum proposalInputDatum
|
, withDatum proposalInputDatum
|
||||||
, withRef proposalRef
|
, withRef proposalRef
|
||||||
|
, withRedeemer proposalRedeemer
|
||||||
]
|
]
|
||||||
, output $
|
, output $
|
||||||
mconcat
|
mconcat
|
||||||
[ script proposalValidatorHash
|
[ script proposalValidatorHash
|
||||||
, withValue (sortValue (pst <> minAda))
|
, withValue proposalValue
|
||||||
, withDatum proposalOutputDatum
|
, withDatum proposalOutputDatum
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
validTimeRange :: POSIXTimeRange
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
validTimeRange =
|
validTimeRange =
|
||||||
closedBoundedInterval
|
closedBoundedInterval
|
||||||
(coerce proposalInputDatum.startingTime + 1)
|
(coerce proposalInputDatum.startingTime + 1)
|
||||||
|
|
@ -204,7 +301,12 @@ cosign ps = builder
|
||||||
+ proposalInputDatum.timingConfig.draftTime - 1
|
+ proposalInputDatum.timingConfig.draftTime - 1
|
||||||
)
|
)
|
||||||
|
|
||||||
---
|
sig =
|
||||||
|
mkSigner
|
||||||
|
ps.stakeParameters.stakeOwner
|
||||||
|
ps.transactionParameters.signedBy
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
builder =
|
builder =
|
||||||
mconcat
|
mconcat
|
||||||
|
|
@ -212,87 +314,107 @@ cosign ps = builder
|
||||||
, timeRange validTimeRange
|
, timeRange validTimeRange
|
||||||
, proposalBuilder
|
, proposalBuilder
|
||||||
, stakeBuilder
|
, stakeBuilder
|
||||||
|
, signedWith sig
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | Reference index of the proposal UTXO.
|
--------------------------------------------------------------------------------
|
||||||
proposalRefIdx :: Integer
|
|
||||||
proposalRefIdx = 1
|
|
||||||
|
|
||||||
-- | Spend the proposal ST.
|
|
||||||
proposalRef :: TxOutRef
|
|
||||||
proposalRef = TxOutRef proposalTxRef proposalRefIdx
|
|
||||||
|
|
||||||
-- | Consume the given stake.
|
|
||||||
mkStakeRef :: Int -> TxOutRef
|
|
||||||
mkStakeRef idx =
|
|
||||||
TxOutRef
|
|
||||||
stakeTxRef
|
|
||||||
$ proposalRefIdx + 1 + fromIntegral idx
|
|
||||||
|
|
||||||
-- | Create a proposal redeemer which cosigns with the new cosginers.
|
|
||||||
mkProposalRedeemer :: Parameters -> ProposalRedeemer
|
|
||||||
mkProposalRedeemer = Cosign . sort . (.newCosigners)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
-- | Create a valid parameters that cosign the proposal with a given number of cosigners.
|
|
||||||
validCosignNParameters :: Int -> Parameters
|
|
||||||
validCosignNParameters n
|
|
||||||
| n > 0 =
|
|
||||||
Parameters
|
|
||||||
{ newCosigners = take n (fmap PubKeyCredential pubKeyHashes)
|
|
||||||
, proposalStatus = Draft
|
|
||||||
}
|
|
||||||
| otherwise = error "Number of cosigners should be positive"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{- | Parameters that make 'cosign' yield duplicate cosigners.
|
|
||||||
Invalid for the ptoposal validator, perfectly valid for stake validator.
|
|
||||||
-}
|
|
||||||
duplicateCosignersParameters :: Parameters
|
|
||||||
duplicateCosignersParameters =
|
|
||||||
Parameters
|
|
||||||
{ newCosigners = [PubKeyCredential proposalCreator]
|
|
||||||
, proposalStatus = Draft
|
|
||||||
}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
{- | Generate a list of parameters that sets proposal status to something other than 'Draft'.
|
|
||||||
Invalid for the ptoposal validator, perfectly valid for stake validator.
|
|
||||||
-}
|
|
||||||
statusNotDraftCosignNParameters :: Int -> [Parameters]
|
|
||||||
statusNotDraftCosignNParameters n =
|
|
||||||
map
|
|
||||||
( \st ->
|
|
||||||
Parameters
|
|
||||||
{ newCosigners = take n (fmap PubKeyCredential pubKeyHashes)
|
|
||||||
, proposalStatus = st
|
|
||||||
}
|
|
||||||
)
|
|
||||||
[VotingReady, Locked, Finished]
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
-- | Create a test tree given the parameters. Both the proposal validator and stake validator will be run.
|
|
||||||
mkTestTree ::
|
mkTestTree ::
|
||||||
-- | The name of the test group.
|
|
||||||
String ->
|
String ->
|
||||||
Parameters ->
|
ParameterBundle ->
|
||||||
-- | Are the parameters valid for the proposal validator?
|
Validity ->
|
||||||
Bool ->
|
|
||||||
SpecificationTree
|
SpecificationTree
|
||||||
mkTestTree name ps isValid = proposal
|
mkTestTree name ps val =
|
||||||
|
group name [proposal, stake]
|
||||||
where
|
where
|
||||||
spend = mkSpending cosign ps
|
spend = mkSpending cosign ps
|
||||||
|
|
||||||
proposal =
|
proposal =
|
||||||
let proposalInputDatum = mkProposalInputDatum ps
|
testValidator
|
||||||
in testValidator
|
val.forProposalValidator
|
||||||
isValid
|
"proposal"
|
||||||
(name <> ": proposal")
|
|
||||||
agoraScripts.compiledProposalValidator
|
agoraScripts.compiledProposalValidator
|
||||||
proposalInputDatum
|
(mkProposalInputDatum ps)
|
||||||
(mkProposalRedeemer ps)
|
proposalRedeemer
|
||||||
(spend proposalRef)
|
(spend proposalRef)
|
||||||
|
|
||||||
|
stake =
|
||||||
|
testValidator
|
||||||
|
val.forStakeValidator
|
||||||
|
"stake"
|
||||||
|
agoraScripts.compiledStakeValidator
|
||||||
|
(mkStakeInputDatum ps)
|
||||||
|
stakeRedeemer
|
||||||
|
(spend stakeRef)
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
totallyValid :: ParameterBundle
|
||||||
|
totallyValid =
|
||||||
|
ParameterBundle
|
||||||
|
{ stakeParameters =
|
||||||
|
StakeParameters
|
||||||
|
{ gtAmount = Sufficient
|
||||||
|
, stakeOwner = Other
|
||||||
|
, dontUpdateLocks = False
|
||||||
|
}
|
||||||
|
, proposalParameters =
|
||||||
|
ProposalParameters
|
||||||
|
{ proposalStatus = Draft
|
||||||
|
, dontUpdateCosigners = False
|
||||||
|
}
|
||||||
|
, transactionParameters =
|
||||||
|
TransactionParameters
|
||||||
|
{ signedBy =
|
||||||
|
Owner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insufficientStakedAmount :: ParameterBundle
|
||||||
|
insufficientStakedAmount =
|
||||||
|
totallyValid
|
||||||
|
{ stakeParameters =
|
||||||
|
totallyValid.stakeParameters
|
||||||
|
{ gtAmount = Insufficient
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
locksNotUpdated :: ParameterBundle
|
||||||
|
locksNotUpdated =
|
||||||
|
totallyValid
|
||||||
|
{ stakeParameters =
|
||||||
|
totallyValid.stakeParameters
|
||||||
|
{ dontUpdateLocks = True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicateCosigners :: ParameterBundle
|
||||||
|
duplicateCosigners =
|
||||||
|
totallyValid
|
||||||
|
{ stakeParameters =
|
||||||
|
totallyValid.stakeParameters
|
||||||
|
{ stakeOwner = Creator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cosignersNotUpdated :: ParameterBundle
|
||||||
|
cosignersNotUpdated =
|
||||||
|
totallyValid
|
||||||
|
{ proposalParameters =
|
||||||
|
totallyValid.proposalParameters
|
||||||
|
{ dontUpdateCosigners = True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cosignAfterDraft :: [ParameterBundle]
|
||||||
|
cosignAfterDraft =
|
||||||
|
map
|
||||||
|
( \s ->
|
||||||
|
totallyValid
|
||||||
|
{ proposalParameters =
|
||||||
|
totallyValid.proposalParameters
|
||||||
|
{ proposalStatus = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
[VotingReady, Locked, Finished]
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,7 @@ unlock ps = builder
|
||||||
not
|
not
|
||||||
. ( \case
|
. ( \case
|
||||||
Created pid -> c && pid == defProposalId
|
Created pid -> c && pid == defProposalId
|
||||||
|
Cosigned pid -> c && pid == defProposalId
|
||||||
Voted pid _ -> v && pid == defProposalId
|
Voted pid _ -> v && pid == defProposalId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ instance Default ProposalThresholds where
|
||||||
, create = Tagged 1
|
, create = Tagged 1
|
||||||
, toVoting = Tagged 100
|
, toVoting = Tagged 100
|
||||||
, vote = Tagged 100
|
, vote = Tagged 100
|
||||||
|
, cosign = Tagged 100
|
||||||
}
|
}
|
||||||
|
|
||||||
authorityTokenSymbol :: CurrencySymbol
|
authorityTokenSymbol :: CurrencySymbol
|
||||||
|
|
|
||||||
|
|
@ -90,41 +90,39 @@ specs =
|
||||||
"validator"
|
"validator"
|
||||||
[ group
|
[ group
|
||||||
"cosignature"
|
"cosignature"
|
||||||
$ let cosignerCases = [1, 5, 10]
|
[ Cosign.mkTestTree
|
||||||
|
"legal"
|
||||||
mkLegalGroup nCosigners =
|
Cosign.totallyValid
|
||||||
Cosign.mkTestTree
|
(Cosign.Validity True True)
|
||||||
(unwords ["with", show nCosigners, "cosigners"])
|
, group
|
||||||
(Cosign.validCosignNParameters nCosigners)
|
|
||||||
True
|
|
||||||
legalGroup =
|
|
||||||
group "legal" $
|
|
||||||
map mkLegalGroup cosignerCases
|
|
||||||
|
|
||||||
mkIllegalStatusNotDraftGroup nCosigners =
|
|
||||||
group (unwords ["with", show nCosigners, "cosigners"]) $
|
|
||||||
map
|
|
||||||
( \ps ->
|
|
||||||
Cosign.mkTestTree
|
|
||||||
("status: " <> show ps.proposalStatus)
|
|
||||||
ps
|
|
||||||
False
|
|
||||||
)
|
|
||||||
(Cosign.statusNotDraftCosignNParameters nCosigners)
|
|
||||||
illegalStatusNotDraftGroup =
|
|
||||||
group "proposal status not Draft" $
|
|
||||||
map mkIllegalStatusNotDraftGroup cosignerCases
|
|
||||||
|
|
||||||
illegalGroup =
|
|
||||||
group
|
|
||||||
"illegal"
|
"illegal"
|
||||||
[ Cosign.mkTestTree
|
[ 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"
|
"duplicate cosigners"
|
||||||
Cosign.duplicateCosignersParameters
|
Cosign.duplicateCosigners
|
||||||
False
|
(Cosign.Validity False True)
|
||||||
, illegalStatusNotDraftGroup
|
, 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
|
||||||
|
]
|
||||||
]
|
]
|
||||||
in [legalGroup, illegalGroup]
|
|
||||||
, group
|
, group
|
||||||
"voting"
|
"voting"
|
||||||
[ group
|
[ group
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue