be more consistent in use of "period", "state", etc wrt. proposals

- specify maximum cosigners requirement in spec.
- remove silly qualified names in Proposal impl.
This commit is contained in:
Emily Martins 2022-04-27 14:43:55 +02:00
parent 9dd5bed05e
commit 2865f2f093
4 changed files with 39 additions and 34 deletions

View file

@ -107,6 +107,7 @@ proposal =
Value.assetClass govSymbol ""
, stakeSTAssetClass =
Value.assetClass stakeSymbol ""
, maximumCosigners = 6
}
proposalPolicySymbol :: CurrencySymbol

View file

@ -84,8 +84,10 @@ newtype ResultTag = ResultTag {getResultTag :: Integer}
deriving stock (Eq, Show, Ord)
deriving newtype (PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData)
{- | The "status" of the proposal. This is only useful for state transitions,
as opposed to time-based "phases".
{- | The "status" of the proposal. This is only useful for state transitions that
need to happen as a result of a transaction as opposed to time-based "periods".
See the note on wording & the state machine in the tech-design.
If the proposal is 'VotingReady', for instance, that doesn't necessarily
mean that voting is possible, as this also requires the timing to be right.
@ -220,7 +222,7 @@ data ProposalRedeemer
-- === @* -> 'Finished'@:
--
-- If the proposal has run out of time for the current 'ProposalStatus', it will always be possible
-- to transition into 'Finished' state, because it has expired (and failed).
-- to transition into 'Finished' status, because it has expired (and failed).
AdvanceProposal
deriving stock (Eq, Show, GHC.Generic)
@ -236,6 +238,8 @@ PlutusTx.makeIsDataIndexed
data Proposal = Proposal
{ governorSTAssetClass :: AssetClass
, stakeSTAssetClass :: AssetClass
, maximumCosigners :: Integer
-- ^ Arbitrary limit for maximum amount of cosigners on a proposal.
}
deriving stock (Show, Eq)
@ -395,11 +399,11 @@ deriving via (DerivePConstantViaData ProposalRedeemer PProposalRedeemer) instanc
--------------------------------------------------------------------------------
{- | Check for various invariants a proposal must uphold.
This can be used to check both upopn creation and
This can be used to check both upon creation and
upon any following state transitions in the proposal.
-}
proposalDatumValid :: Term s (Agora.Proposal.PProposalDatum :--> PBool)
proposalDatumValid =
proposalDatumValid :: Proposal -> Term s (Agora.Proposal.PProposalDatum :--> PBool)
proposalDatumValid proposal =
phoistAcyclic $
plam $ \datum' -> P.do
datum <- pletFields @'["effects", "cosigners"] $ datum'
@ -420,5 +424,5 @@ proposalDatumValid =
(#&&)
[ ptraceIfFalse "Proposal has at least one ResultTag has no effects" atLeastOneNegativeResult
, ptraceIfFalse "Proposal has at least one cosigner" $ pnotNull # pfromData datum.cosigners
, ptraceIfFalse "Proposal has at most five cosigners" $ plength # (pfromData datum.cosigners) #< 6
, ptraceIfFalse "Proposal has at most five cosigners" $ plength # (pfromData datum.cosigners) #<= pconstant proposal.maximumCosigners
]

View file

@ -48,20 +48,20 @@ import Plutus.V1.Ledger.Value (AssetClass (AssetClass))
NOTE: The governor needs to check that the datum is correct
and sent to the right address.
-}
proposalPolicy :: Agora.Proposal.Proposal -> ClosedTerm Plutarch.Api.V1.PMintingPolicy
proposalPolicy :: Proposal -> ClosedTerm PMintingPolicy
proposalPolicy proposal =
plam $ \_redeemer ctx' -> P.do
Plutarch.Api.V1.PScriptContext ctx' <- pmatch ctx'
PScriptContext ctx' <- pmatch ctx'
ctx <- pletFields @'["txInfo", "purpose"] ctx'
Plutarch.Api.V1.PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo
PTxInfo txInfo' <- pmatch $ pfromData ctx.txInfo
txInfo <- pletFields @'["inputs", "mint"] txInfo'
Plutarch.Api.V1.PMinting _ownSymbol <- pmatch $ pfromData ctx.purpose
PMinting _ownSymbol <- pmatch $ pfromData ctx.purpose
let inputs = txInfo.inputs
mintedValue = pfromData txInfo.mint
AssetClass (govCs, govTn) = proposal.governorSTAssetClass
Plutarch.Api.V1.PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
PMinting ownSymbol' <- pmatch $ pfromData ctx.purpose
let mintedProposalST = passetClassValueOf # mintedValue # (passetClass # (pfield @"_0" # ownSymbol') # pconstant "")
passert "Governance state-thread token must move" $
@ -75,15 +75,15 @@ proposalPolicy proposal =
popaque (pconstant ())
-- | Validator for Proposals.
proposalValidator :: Agora.Proposal.Proposal -> ClosedTerm Plutarch.Api.V1.PValidator
proposalValidator :: Proposal -> ClosedTerm PValidator
proposalValidator proposal =
plam $ \datum redeemer ctx' -> P.do
Plutarch.Api.V1.PScriptContext ctx' <- pmatch ctx'
PScriptContext ctx' <- pmatch ctx'
ctx <- pletFields @'["txInfo", "purpose"] ctx'
txInfo <- plet $ pfromData ctx.txInfo
Plutarch.Api.V1.PTxInfo txInfo' <- pmatch txInfo
PTxInfo txInfo' <- pmatch txInfo
txInfoF <- pletFields @'["inputs", "mint", "datums", "signatories"] txInfo'
Plutarch.Api.V1.PSpending ((pfield @"_0" #) -> txOutRef) <- pmatch $ pfromData ctx.purpose
PSpending ((pfield @"_0" #) -> txOutRef) <- pmatch $ pfromData ctx.purpose
PJust txOut <- pmatch $ findTxOutByTxOutRef # txOutRef # txInfoF.inputs
txOutF <- pletFields @'["address", "value"] $ txOut
@ -114,13 +114,13 @@ proposalValidator proposal =
signedBy <- plet $ ptxSignedBy # txInfoF.signatories
pmatch proposalRedeemer $ \case
Agora.Proposal.PVote _r -> P.do
PVote _r -> P.do
passert "ST at inputs must be 1" $
spentST #== 1
popaque (pconstant ())
--------------------------------------------------------------------------
Agora.Proposal.PCosign r -> P.do
PCosign r -> P.do
newSigs <- plet $ pfield @"newCosigners" # r
passert "ST at inputs must be 1" $
@ -143,14 +143,14 @@ proposalValidator proposal =
# newSigs
passert "Signatures are correctly added to cosignature list" $
anyOutput @Agora.Proposal.PProposalDatum # ctx.txInfo
anyOutput @PProposalDatum # ctx.txInfo
#$ plam
$ \newValue address newProposalDatum -> P.do
let correctDatum =
pdata newProposalDatum
#== pdata
( mkRecordConstr
Agora.Proposal.PProposalDatum
PProposalDatum
( #proposalId .= proposalF.proposalId
.& #effects .= proposalF.effects
.& #status .= proposalF.status
@ -170,13 +170,13 @@ proposalValidator proposal =
popaque (pconstant ())
--------------------------------------------------------------------------
Agora.Proposal.PUnlock _r -> P.do
PUnlock _r -> P.do
passert "ST at inputs must be 1" $
spentST #== 1
popaque (pconstant ())
--------------------------------------------------------------------------
Agora.Proposal.PAdvanceProposal _r -> P.do
PAdvanceProposal _r -> P.do
passert "ST at inputs must be 1" $
spentST #== 1

View file

@ -35,9 +35,9 @@ Initiating a proposal requires the proposer to have more than a certain amount o
### Voting stages
The life-cycle of a proposal is neatly represented by a state machine, with the 'draft' phase being the initial state, and 'executed' and 'failed' being the terminating states.
The life-cycle of a proposal is neatly represented by a state machine, with the 'draft' state being the initial state, and 'executed' and 'failed' being the terminating states.
**Please note that this state-machine representation is purely conceptual and should not be expected to reflect technical implementation.** This is because some state transitions in the state machine representation don't need to happen in the actual implementation as a transaction. A key example is going from the "lock" phase to the "execution" phase. The only thing that needs to happen is that time goes by. So under the hood, they are represented the same in the Proposal's datum.
**Please note that this state-machine representation is purely conceptual and should not be expected to reflect technical implementation.** This is because some state transitions in the state machine representation don't need to happen in the actual implementation as a transaction. A key example is going from the "lock" phase to the "execution" phase. The only thing that needs to happen is that time goes by. So under the hood, they are represented the same in the Proposal's datum. Furthermore, in order to make our wording consistent, we use _"period"_ to mean a time-based, and _"status"_ to mean what is encoded in the datum. "State", then, refers to the more vague notion of what the state machine would look like.
> Emily 2022-04-27: This is quite confusing still, I feel. @Jack, could you try to reword this and make it more clear?
@ -54,21 +54,21 @@ Consider the following 'stages' of a proposal:
- `L`: the length of the locking period.
- `E`: the length of the execution period.
| Action | Valid POSIXTimeRange | Valid _stored_ state(s) |
|-------------------------------------|-------------------------------------|-------------------------|
| Witness | \[S, ∞) | \* |
| Cosign | \[S, S + D) | Draft |
| AdvanceProposal | \[S, S + D) | Draft |
| Vote | \[S + D, S + D + V) | Voting |
| Unlock | \[S + D, ∞) | \* |
| CountVotes | \[S + D + V, S + D + V + L) | Voting |
| ExecuteProposal (if quorum reached) | \[S + D + V + L, S + D + V + L + E) | Voting |
| Action | Valid POSIXTimeRange | Valid _stored_ status(es) |
|-------------------------------------|-------------------------------------|---------------------------|
| Witness | \[S, ∞) | \* |
| Cosign | \[S, S + D) | Draft |
| AdvanceProposal | \[S, S + D) | Draft |
| Vote | \[S + D, S + D + V) | Voting |
| Unlock | \[S + D, ∞) | \* |
| CountVotes | \[S + D + V, S + D + V + L) | Voting |
| ExecuteProposal (if quorum reached) | \[S + D + V + L, S + D + V + L + E) | Voting |
> Jack 2022-02-02: I will consider revising this table further at a later time.
#### Draft phase
During the draft phase, a new UTXO at the proposal script has been created. At this stage, only votes in favor of co-signing the draft are counted. For the proposal to transition to the voting phase, a threshold of GT will have to be staked backing the proposal. This threshold will be determined on a per-system basis and could itself be a 'governable' parameter. It's important to note that cosignatures are not locking votes. Cosignatures are more like a delegated approval to a proposal. The sum of all cosignatures must tally to the threshold, and all cosigner stake datums must fit into a single transaction to witness their size.
During the draft phase, a new UTXO at the proposal script has been created. At this stage, only votes in favor of co-signing the draft are counted. For the proposal to transition to the voting phase, a threshold of GT will have to be staked backing the proposal. This threshold will be determined on a per-system basis and could itself be a 'governable' parameter. It's important to note that cosignatures are not locking votes. Cosignatures are more like a delegated approval to a proposal. The sum of all cosignatures must tally to the threshold, and all cosigner stake datums must fit into a single transaction to witness their size. A limit on the maximum amount of cosigners is placed in order to prevent a situation where the stake datums no longer fit in the transaction. The number doesn't matter and may be expressed in a parametrized way.
#### Voting phase