From 70d3c01af4c722ed3de75c812fa9991c11e39f6f Mon Sep 17 00:00:00 2001 From: fanghr Date: Sat, 28 May 2022 22:11:23 +0800 Subject: [PATCH] add tests and samples of advancing proposals --- .../Sample/Effect/GovernorMutation.hs | 7 +- agora-sample/Sample/Governor.hs | 13 +- agora-sample/Sample/Proposal.hs | 411 +++++++++++++++++- agora-sample/Sample/Shared.hs | 18 +- agora-spec/Spec/Effect/GovernorMutation.hs | 4 +- agora-spec/Spec/Governor.hs | 6 +- agora-spec/Spec/Proposal.hs | 196 ++++++++- bench.csv | 6 + 8 files changed, 626 insertions(+), 35 deletions(-) diff --git a/agora-sample/Sample/Effect/GovernorMutation.hs b/agora-sample/Sample/Effect/GovernorMutation.hs index b2f851f..49903be 100644 --- a/agora-sample/Sample/Effect/GovernorMutation.hs +++ b/agora-sample/Sample/Effect/GovernorMutation.hs @@ -45,7 +45,6 @@ import Plutus.V1.Ledger.Value qualified as Value import Sample.Shared ( authorityTokenSymbol, - defaultProposalThresholds, govAssetClass, govValidatorAddress, governor, @@ -113,7 +112,7 @@ mkEffectTxInfo newGovDatum = governorInputDatum' :: GovernorDatum governorInputDatum' = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 0 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -175,7 +174,7 @@ mkEffectTxInfo newGovDatum = validNewGovernorDatum :: GovernorDatum validNewGovernorDatum = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 42 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -185,7 +184,7 @@ invalidNewGovernorDatum :: GovernorDatum invalidNewGovernorDatum = GovernorDatum { proposalThresholds = - defaultProposalThresholds + def { countVoting = Tagged (-1) } , nextProposalId = ProposalId 42 diff --git a/agora-sample/Sample/Governor.hs b/agora-sample/Sample/Governor.hs index b05e3a1..c2159cd 100644 --- a/agora-sample/Sample/Governor.hs +++ b/agora-sample/Sample/Governor.hs @@ -70,7 +70,6 @@ import Agora.Stake ( import Sample.Shared ( authorityTokenSymbol, - defaultProposalThresholds, govAssetClass, govSymbol, govValidatorAddress, @@ -119,7 +118,7 @@ mintGST = governorOutputDatum' :: GovernorDatum governorOutputDatum' = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 0 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -214,7 +213,7 @@ createProposal = governorInputDatum' :: GovernorDatum governorInputDatum' = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = thisProposalId , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -245,7 +244,7 @@ createProposal = , effects = effects , status = Draft , cosigners = [signer] - , thresholds = defaultProposalThresholds + , thresholds = def , votes = emptyVotesFor effects , timingConfig = def , startingTime = proposalStartingTimeFromTimeRange validTimeRange @@ -392,7 +391,7 @@ mintGATs = governorInputDatum' :: GovernorDatum governorInputDatum' = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 5 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -428,7 +427,7 @@ mintGATs = , effects = effects , status = Locked , cosigners = [signer, signer2] - , thresholds = defaultProposalThresholds + , thresholds = def , votes = proposalVotes , timingConfig = def , startingTime = ProposalStartingTime 10 @@ -587,7 +586,7 @@ mutateState = governorInputDatum' :: GovernorDatum governorInputDatum' = GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 5 , proposalTimings = def , createProposalTimeRangeMaxWidth = def diff --git a/agora-sample/Sample/Proposal.hs b/agora-sample/Sample/Proposal.hs index 9dbdb93..9af01ce 100644 --- a/agora-sample/Sample/Proposal.hs +++ b/agora-sample/Sample/Proposal.hs @@ -13,6 +13,12 @@ module Sample.Proposal ( stakeRef, voteOnProposal, VotingParameters (..), + advanceProposalSuccess, + advanceProposalFailureTimeout, + TransitionParameters (..), + advanceFinishedPropsoal, + advanceProposalInsufficientVotes, + advancePropsoalWithsStake, ) where -------------------------------------------------------------------------------- @@ -27,6 +33,8 @@ import Plutus.V1.Ledger.Api ( Address (Address), Credential (ScriptCredential), Datum (Datum), + DatumHash, + POSIXTime, POSIXTimeRange, PubKeyHash, ScriptContext (..), @@ -36,6 +44,7 @@ import Plutus.V1.Ledger.Api ( TxInfo (..), TxOut (TxOut, txOutAddress, txOutDatumHash, txOutValue), TxOutRef (TxOutRef), + ValidatorHash, ) import Plutus.V1.Ledger.Value qualified as Value import PlutusTx.AssocMap qualified as AssocMap @@ -50,6 +59,7 @@ import Agora.Proposal ( ProposalDatum (..), ProposalId (..), ProposalStatus (..), + ProposalThresholds (..), ProposalVotes (..), ResultTag (..), emptyVotesFor, @@ -84,7 +94,7 @@ proposalCreation = , effects = effects , status = Draft , cosigners = [signer] - , thresholds = defaultProposalThresholds + , thresholds = def , votes = emptyVotesFor effects , timingConfig = def , startingTime = proposalStartingTimeFromTimeRange validTimeRange @@ -96,7 +106,7 @@ proposalCreation = Datum ( toBuiltinData $ GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 0 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -107,7 +117,7 @@ proposalCreation = Datum ( toBuiltinData $ GovernorDatum - { proposalThresholds = defaultProposalThresholds + { proposalThresholds = def , nextProposalId = ProposalId 1 , proposalTimings = def , createProposalTimeRangeMaxWidth = def @@ -185,7 +195,7 @@ cosignProposal newSigners = , effects = effects , status = Draft , cosigners = [signer] - , thresholds = defaultProposalThresholds + , thresholds = def , votes = emptyVotesFor effects , timingConfig = def , startingTime = ProposalStartingTime 0 @@ -306,7 +316,7 @@ voteOnProposal params = , effects = effects , status = VotingReady , cosigners = [stakeOwner] - , thresholds = defaultProposalThresholds + , thresholds = def , votes = ProposalVotes initialVotes , timingConfig = def , startingTime = ProposalStartingTime 0 @@ -375,7 +385,7 @@ voteOnProposal params = --- - -- Off-chain code should do exactly like this: prepend new lock to the list. + -- Off-chain code should do exactly like this: prepend new lock toStatus the list. updatedLocks :: [ProposalLock] updatedLocks = ProposalLock params.voteFor proposalInputDatum'.proposalId : existingLocks @@ -415,3 +425,392 @@ voteOnProposal params = , txInfoData = datumPair <$> [proposalInputDatum, proposalOutputDatum, stakeInputDatum, stakeOutputDatum] , txInfoId = "827598fb2d69a896bbd9e645bb14c307df907f422b39eecbe4d6329bc30b428c" } + +-------------------------------------------------------------------------------- + +-- | Parameters for state transition of proposals. +data TransitionParameters = TransitionParameters + { -- The initial status of the propsoal. + initialProposalStatus :: ProposalStatus + , -- The starting time of the propsoal. + proposalStartingTime :: ProposalStartingTime + } + +-- | Create a 'TxInfo' that update the status of a proposal. +mkTransitionTxInfo :: + -- | Initial state of the proposal. + ProposalStatus -> + -- | Next state of the proposal. + ProposalStatus -> + -- | Effects. + AssocMap.Map ResultTag (AssocMap.Map ValidatorHash DatumHash) -> + -- | Votes. + ProposalVotes -> + -- | Starting time of the proposal. + ProposalStartingTime -> + -- | Valid time range of the transaction. + POSIXTimeRange -> + TxInfo +mkTransitionTxInfo from to effects votes startingTime timeRange = + let pst = Value.singleton proposalPolicySymbol "" 1 + + --- + + proposalInputDatum' :: ProposalDatum + proposalInputDatum' = + ProposalDatum + { proposalId = ProposalId 0 + , effects = effects + , status = from + , cosigners = [signer] + , thresholds = def + , votes = votes + , timingConfig = def + , startingTime = startingTime + } + proposalInputDatum :: Datum + proposalInputDatum = Datum $ toBuiltinData proposalInputDatum' + proposalInput :: TxOut + proposalInput = + TxOut + { txOutAddress = proposalValidatorAddress + , txOutValue = pst + , txOutDatumHash = Just $ toDatumHash proposalInputDatum + } + + --- + + proposalOutputDatum' :: ProposalDatum + proposalOutputDatum' = + proposalInputDatum' + { status = to + } + proposalOutputDatum :: Datum + proposalOutputDatum = Datum $ toBuiltinData proposalOutputDatum' + proposalOutput :: TxOut + proposalOutput = + proposalInput + { txOutValue = proposalInput.txOutValue <> minAda + , txOutDatumHash = Just $ toDatumHash proposalOutputDatum + } + in TxInfo + { txInfoInputs = [TxInInfo proposalRef proposalInput] + , txInfoOutputs = [proposalOutput] + , txInfoFee = Value.singleton "" "" 2 + , txInfoMint = mempty + , txInfoDCert = [] + , txInfoWdrl = [] + , txInfoValidRange = timeRange + , txInfoSignatories = [signer] + , txInfoData = datumPair <$> [proposalInputDatum, proposalOutputDatum] + , txInfoId = "95ba4015e30aef16a3461ea97a779f814aeea6b8009d99a94add4b8293be737a" + } + +{- | Create a valid 'TxInfo' that advances a proposal, given the parameters. + Note that 'TransitionParameters.initialProposalStatus' should not be 'Finished'. +-} +advanceProposalSuccess :: TransitionParameters -> TxInfo +advanceProposalSuccess params = + let -- Status of the output proposal. + toStatus :: ProposalStatus + toStatus = case params.initialProposalStatus of + Draft -> VotingReady + VotingReady -> Locked + Locked -> Finished + Finished -> error "Cannot advance 'Finished' proposal" + + effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + + emptyVotes@(ProposalVotes emptyVotes') = emptyVotesFor effects + + -- Set the vote count of outcome 0 to @def.countingVoting + 1@, + -- meaning that outcome 0 will be the winner. + outcome0WinningVotes = + ProposalVotes $ + updateMap + (\_ -> Just $ untag (def :: ProposalThresholds).countVoting + 1) + (ResultTag 0) + emptyVotes' + + votes :: ProposalVotes + votes = case params.initialProposalStatus of + Draft -> emptyVotes + -- With sufficient votes + _ -> outcome0WinningVotes + + proposalStartingTime :: POSIXTime + proposalStartingTime = + let (ProposalStartingTime startingTime) = params.proposalStartingTime + in startingTime + + timeRange :: POSIXTimeRange + timeRange = case params.initialProposalStatus of + -- [S + 1, S + D - 1] + Draft -> + closedBoundedInterval + (proposalStartingTime + 1) + (proposalStartingTime + (def :: ProposalTimingConfig).draftTime - 1) + -- [S + D + 1, S + D + V - 1] + VotingReady -> + closedBoundedInterval + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + 1 + ) + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime - 1 + ) + -- [S + D + V + L + 1, S + + D + V + L + E - 1] + Locked -> + closedBoundedInterval + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + (def :: ProposalTimingConfig).lockingTime + + 1 + ) + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + (def :: ProposalTimingConfig).lockingTime + + (def :: ProposalTimingConfig).executingTime - 1 + ) + Finished -> error "Cannot advance 'Finished' proposal" + in mkTransitionTxInfo + params.initialProposalStatus + toStatus + effects + votes + params.proposalStartingTime + timeRange + +{- | Create a valid 'TxInfo' that advances a proposal to failed state, given the parameters. + The reason why the proposal fails is the proposal has ran out of time. + Note that 'TransitionParameters.initialProposalStatus' should not be 'Finished'. +-} +advanceProposalFailureTimeout :: TransitionParameters -> TxInfo +advanceProposalFailureTimeout params = + let effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + + emptyVotes@(ProposalVotes emptyVotes') = emptyVotesFor effects + + -- Set the vote count of outcome 0 to @def.countingVoting + 1@, + -- meaning that outcome 0 will be the winner. + outcome0WinningVotes = + ProposalVotes $ + updateMap + (\_ -> Just $ untag (def :: ProposalThresholds).countVoting + 1) + (ResultTag 0) + emptyVotes' + + votes :: ProposalVotes + votes = case params.initialProposalStatus of + Draft -> emptyVotes + -- With sufficient votes + _ -> outcome0WinningVotes + + proposalStartingTime :: POSIXTime + proposalStartingTime = + let (ProposalStartingTime startingTime) = params.proposalStartingTime + in startingTime + + timeRange :: POSIXTimeRange + timeRange = case params.initialProposalStatus of + -- [S + D + 1, S + D + V - 1] + Draft -> + closedBoundedInterval + (proposalStartingTime + (def :: ProposalTimingConfig).draftTime + 1) + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime - 1 + ) + -- [S + D + V + 1, S + D + V + L -1] + VotingReady -> + closedBoundedInterval + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + 1 + ) + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + (def :: ProposalTimingConfig).lockingTime - 1 + ) + -- [S + D + V + L + E + 1, S + D + V + L + E + 100] + Locked -> + closedBoundedInterval + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + (def :: ProposalTimingConfig).lockingTime + + (def :: ProposalTimingConfig).executingTime + + 1 + ) + ( proposalStartingTime + + (def :: ProposalTimingConfig).draftTime + + (def :: ProposalTimingConfig).votingTime + + (def :: ProposalTimingConfig).lockingTime + + (def :: ProposalTimingConfig).executingTime + + 100 + ) + Finished -> error "Cannot advance 'Finished' proposal" + in mkTransitionTxInfo + params.initialProposalStatus + Finished + effects + votes + params.proposalStartingTime + timeRange + +-- | An invalid 'TxInfo' that tries to advance a 'VotingReady' proposal without sufficient votes. +advanceProposalInsufficientVotes :: TxInfo +advanceProposalInsufficientVotes = + let effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + + -- Insufficient votes. + votes = emptyVotesFor effects + + proposalStartingTime = 0 + + -- Valid time range. + -- [S + D + 1, S + V - 1] + timeRange = + closedBoundedInterval + (proposalStartingTime + (def :: ProposalTimingConfig).draftTime + 1) + (proposalStartingTime + (def :: ProposalTimingConfig).votingTime - 1) + in mkTransitionTxInfo + VotingReady + Locked + effects + votes + (ProposalStartingTime proposalStartingTime) + timeRange + +-- | An invalid 'TxInfo' that tries to advance a 'Finished' proposal. +advanceFinishedPropsoal :: TxInfo +advanceFinishedPropsoal = + let effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + + -- Set the vote count of outcome 0 to @def.countingVoting + 1@, + -- meaning that outcome 0 will be the winner. + outcome0WinningVotes = + ProposalVotes $ + AssocMap.fromList + [ (ResultTag 0, untag (def :: ProposalThresholds).countVoting + 1) + , (ResultTag 1, 0) + ] + + --- + + timeRange = + closedBoundedInterval + ((def :: ProposalTimingConfig).lockingTime + 1) + ((def :: ProposalTimingConfig).executingTime - 1) + in mkTransitionTxInfo + Finished + Finished + effects + outcome0WinningVotes + (ProposalStartingTime 0) + timeRange + +{- | An illegal 'TxInfo' that tries to use 'AdvanceProposal' with a stake. + From the perspective of stake validator, the transition is valid, + so the proposal validator should reject this. +-} +advancePropsoalWithsStake :: TxInfo +advancePropsoalWithsStake = + let templateTxInfo = + advanceProposalSuccess + TransitionParameters + { initialProposalStatus = VotingReady + , proposalStartingTime = ProposalStartingTime 0 + } + + --- + -- Now we create a new lock on an arbitrary stake + + sst = Value.assetClassValue stakeAssetClass 1 + + --- + + stakeOwner = signer + stakedAmount = 200 + + --- + + existingLocks :: [ProposalLock] + existingLocks = + [ ProposalLock (ResultTag 0) (ProposalId 0) + , ProposalLock (ResultTag 2) (ProposalId 1) + ] + + --- + + stakeInputDatum' :: StakeDatum + stakeInputDatum' = + StakeDatum + { stakedAmount = Tagged stakedAmount + , owner = stakeOwner + , lockedBy = existingLocks + } + stakeInputDatum :: Datum + stakeInputDatum = Datum $ toBuiltinData stakeInputDatum' + stakeInput :: TxOut + stakeInput = + TxOut + { txOutAddress = stakeAddress + , txOutValue = + mconcat + [ sst + , Value.assetClassValue (untag stake.gtClassRef) stakedAmount + , minAda + ] + , txOutDatumHash = Just $ toDatumHash stakeInputDatum + } + + --- + + updatedLocks :: [ProposalLock] + updatedLocks = ProposalLock (ResultTag 42) (ProposalId 27) : existingLocks + + --- + + stakeOutputDatum' :: StakeDatum + stakeOutputDatum' = + stakeInputDatum' + { lockedBy = updatedLocks + } + stakeOutputDatum :: Datum + stakeOutputDatum = Datum $ toBuiltinData stakeOutputDatum' + stakeOutput :: TxOut + stakeOutput = + stakeInput + { txOutDatumHash = Just $ toDatumHash stakeOutputDatum + } + in templateTxInfo + { txInfoInputs = TxInInfo stakeRef stakeInput : templateTxInfo.txInfoInputs + , txInfoOutputs = stakeOutput : templateTxInfo.txInfoOutputs + , txInfoData = + (datumPair <$> [stakeInputDatum, stakeOutputDatum]) + <> templateTxInfo.txInfoData + , txInfoSignatories = [stakeOwner] + } diff --git a/agora-sample/Sample/Shared.hs b/agora-sample/Sample/Shared.hs index 41292ff..4182f52 100644 --- a/agora-sample/Sample/Shared.hs +++ b/agora-sample/Sample/Shared.hs @@ -33,7 +33,6 @@ module Sample.Shared ( gstUTXORef, -- ** Proposal - defaultProposalThresholds, proposal, proposalPolicySymbol, proposalValidatorHash, @@ -184,13 +183,16 @@ proposalValidatorHash = proposalValidatorHashFromGovernor governor proposalValidatorAddress :: Address proposalValidatorAddress = scriptHashAddress proposalValidatorHash -defaultProposalThresholds :: ProposalThresholds -defaultProposalThresholds = - ProposalThresholds - { countVoting = Tagged 1000 - , create = Tagged 1 - , startVoting = Tagged 10 - } +{- | Default value of 'Agora.Proposal.ProposalThresholds'. + For testing purpose only. +-} +instance Default ProposalThresholds where + def = + ProposalThresholds + { countVoting = Tagged 1000 + , create = Tagged 1 + , startVoting = Tagged 10 + } authorityToken :: AuthorityToken authorityToken = authorityTokenFromGovernor governor diff --git a/agora-spec/Spec/Effect/GovernorMutation.hs b/agora-spec/Spec/Effect/GovernorMutation.hs index d38d382..352d071 100644 --- a/agora-spec/Spec/Effect/GovernorMutation.hs +++ b/agora-spec/Spec/Effect/GovernorMutation.hs @@ -34,7 +34,7 @@ specs = "governor validator should pass" (governorValidator Shared.governor) ( GovernorDatum - Shared.defaultProposalThresholds + def (ProposalId 0) def def @@ -56,7 +56,7 @@ specs = "governor validator should fail" (governorValidator Shared.governor) ( GovernorDatum - Shared.defaultProposalThresholds + def (ProposalId 0) def def diff --git a/agora-spec/Spec/Governor.hs b/agora-spec/Spec/Governor.hs index 214b4d3..9bb9495 100644 --- a/agora-spec/Spec/Governor.hs +++ b/agora-spec/Spec/Governor.hs @@ -44,7 +44,7 @@ specs = "proposal creation" (governorValidator Shared.governor) ( GovernorDatum - Shared.defaultProposalThresholds + def (ProposalId 0) def def @@ -55,7 +55,7 @@ specs = "GATs minting" (governorValidator Shared.governor) ( GovernorDatum - Shared.defaultProposalThresholds + def (ProposalId 5) def def @@ -66,7 +66,7 @@ specs = "mutate governor state" (governorValidator Shared.governor) ( GovernorDatum - Shared.defaultProposalThresholds + def (ProposalId 5) def def diff --git a/agora-spec/Spec/Proposal.hs b/agora-spec/Spec/Proposal.hs index 697ad13..b66310b 100644 --- a/agora-spec/Spec/Proposal.hs +++ b/agora-spec/Spec/Proposal.hs @@ -15,8 +15,9 @@ import Agora.Proposal ( Proposal (..), ProposalDatum (..), ProposalId (ProposalId), - ProposalRedeemer (Cosign, Vote), - ProposalStatus (Draft, VotingReady), + ProposalRedeemer (..), + ProposalStatus (..), + ProposalThresholds (..), ProposalVotes (ProposalVotes), ResultTag (ResultTag), cosigners, @@ -39,7 +40,7 @@ import Agora.Stake ( ) import Agora.Stake.Scripts (stakeValidator) import Data.Default.Class (Default (def)) -import Data.Tagged (Tagged (Tagged)) +import Data.Tagged (Tagged (Tagged), untag) import Plutus.V1.Ledger.Api (ScriptContext (..), ScriptPurpose (..)) import PlutusTx.AssocMap qualified as AssocMap import Sample.Proposal qualified as Proposal @@ -49,6 +50,7 @@ import Spec.Specification ( SpecificationTree, group, policySucceedsWith, + validatorFailsWith, validatorSucceedsWith, ) @@ -81,7 +83,7 @@ specs = ] , status = Draft , cosigners = [signer] - , thresholds = Shared.defaultProposalThresholds + , thresholds = def , votes = emptyVotesFor $ AssocMap.fromList @@ -115,7 +117,7 @@ specs = ] , status = VotingReady , cosigners = [signer] - , thresholds = Shared.defaultProposalThresholds + , thresholds = def , votes = ProposalVotes ( AssocMap.fromList @@ -158,5 +160,189 @@ specs = (Spending Proposal.stakeRef) ) ] + , group + "advancing" + [ group "successfully advance to next state" $ + map + ( \(name, initialState) -> + validatorSucceedsWith + name + (proposalValidator Shared.proposal) + ( ProposalDatum + { proposalId = ProposalId 0 + , effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + , status = initialState + , cosigners = [signer] + , thresholds = def + , votes = + ProposalVotes + ( AssocMap.fromList + [ + ( ResultTag 0 + , case initialState of + Draft -> 0 + _ -> untag (def :: ProposalThresholds).countVoting + 1 + ) + , (ResultTag 1, 0) + ] + ) + , timingConfig = def + , startingTime = ProposalStartingTime 0 + } + ) + AdvanceProposal + ( ScriptContext + ( Proposal.advanceProposalSuccess + Proposal.TransitionParameters + { Proposal.initialProposalStatus = initialState + , Proposal.proposalStartingTime = ProposalStartingTime 0 + } + ) + (Spending Proposal.proposalRef) + ) + ) + [ ("Draft -> VotringReady", Draft) + , ("VotingReady -> Locked", VotingReady) + , ("Locked -> Finished", Locked) + ] + , group "successfully advance to failed state: timeout" $ + map + ( \(name, initialState) -> + validatorSucceedsWith + name + (proposalValidator Shared.proposal) + ( ProposalDatum + { proposalId = ProposalId 0 + , effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + , status = initialState + , cosigners = [signer] + , thresholds = def + , votes = + ProposalVotes + ( AssocMap.fromList + [ + ( ResultTag 0 + , case initialState of + Draft -> 0 + _ -> untag (def :: ProposalThresholds).countVoting + 1 + ) + , (ResultTag 1, 0) + ] + ) + , timingConfig = def + , startingTime = ProposalStartingTime 0 + } + ) + AdvanceProposal + ( ScriptContext + ( Proposal.advanceProposalFailureTimeout + Proposal.TransitionParameters + { Proposal.initialProposalStatus = initialState + , Proposal.proposalStartingTime = ProposalStartingTime 0 + } + ) + (Spending Proposal.proposalRef) + ) + ) + [ ("Draft -> Finished", Draft) + , ("VotingReady -> Finished", VotingReady) + , ("Locked -> Finished", Locked) + ] + , validatorFailsWith + "illegal: insufficient votes" + (proposalValidator Shared.proposal) + ( ProposalDatum + { proposalId = ProposalId 0 + , effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + , status = VotingReady + , cosigners = [signer] + , thresholds = def + , votes = + ProposalVotes + ( AssocMap.fromList + [ (ResultTag 0, 0) + , (ResultTag 1, 0) + ] + ) + , timingConfig = def + , startingTime = ProposalStartingTime 0 + } + ) + AdvanceProposal + ( ScriptContext + Proposal.advanceProposalInsufficientVotes + (Spending Proposal.proposalRef) + ) + , validatorFailsWith + "illegal: initial state is Finished" + (proposalValidator Shared.proposal) + ( ProposalDatum + { proposalId = ProposalId 0 + , effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + , status = Finished + , cosigners = [signer] + , thresholds = def + , votes = + ProposalVotes + ( AssocMap.fromList + [ (ResultTag 0, untag (def :: ProposalThresholds).countVoting + 1) + , (ResultTag 1, 0) + ] + ) + , timingConfig = def + , startingTime = ProposalStartingTime 0 + } + ) + AdvanceProposal + ( ScriptContext + Proposal.advanceFinishedPropsoal + (Spending Proposal.proposalRef) + ) + , validatorFailsWith + "illegal: with stake input" + (proposalValidator Shared.proposal) + ( ProposalDatum + { proposalId = ProposalId 0 + , effects = + AssocMap.fromList + [ (ResultTag 0, AssocMap.empty) + , (ResultTag 1, AssocMap.empty) + ] + , status = VotingReady + , cosigners = [signer] + , thresholds = def + , votes = + ProposalVotes + ( AssocMap.fromList + [ (ResultTag 0, 0) + , (ResultTag 1, 0) + ] + ) + , timingConfig = def + , startingTime = ProposalStartingTime 0 + } + ) + AdvanceProposal + ( ScriptContext + Proposal.advancePropsoalWithsStake + (Spending Proposal.proposalRef) + ) + ] ] ] diff --git a/bench.csv b/bench.csv index 023f8a5..a3efd41 100644 --- a/bench.csv +++ b/bench.csv @@ -12,6 +12,12 @@ Agora/Proposal/validator/cosignature/proposal,241651391,511819,5772 Agora/Proposal/validator/cosignature/stake,186332635,402961,4561 Agora/Proposal/validator/voting/proposal,240181636,491168,5780 Agora/Proposal/validator/voting/stake,154223940,328703,4614 +Agora/Proposal/validator/advancing/successfully advance to next state/Draft -> VotringReady,129146959,254742,5158 +Agora/Proposal/validator/advancing/successfully advance to next state/VotingReady -> Locked,138455315,275396,5166 +Agora/Proposal/validator/advancing/successfully advance to next state/Locked -> Finished,131138537,260050,5167 +Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/Draft -> Finished,127634992,252012,5160 +Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/VotingReady -> Finished,128625282,254416,5167 +Agora/Proposal/validator/advancing/successfully advance to failed state: timeout/Locked -> Finished,128130137,253214,5167 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct simple,25177457,55883,806 Agora/AuthorityToken/singleAuthorityTokenBurned/Correct many inputs,40266637,88241,900 Agora/Treasury/Validator/Positive/Allows for effect changes,37343572,79744,1841