diff --git a/.gitignore b/.gitignore index 505f72e9e4d..4f778b12fa7 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ specs/**/result* result* specs/**/.ghc.environment.x86_64-linux-* .stack-to-nix.cache + +## Ignore PDFs +*.pdf diff --git a/README.md b/README.md index 806a4967797..64211db2e38 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ following links: - [Explanation of the Small-step-semantics Framework](https://hydra.iohk.io/job/Cardano/cardano-ledger-specs/semanticsSpec/latest/download-by-type/doc-pdf/semantics-spec) - [Simple Script-Based Multi-Signature Scheme](https://hydra.iohk.io/job/Cardano/cardano-ledger-specs/shelleyLedgerSpec/latest/download-by-type/doc-pdf/multi-sig) +In addition, there is an Isabelle/HOL proof of the "no double-spending property" for the Byron Ledger Specification which can be found [here](./byron/ledger/formal-spec/Isabelle/Ledger_Rules.thy). The rendered PDF file can be found [here](./byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization.pdf). + # Repository structure This repo contains formal (LaTeX) and executable (Haskell model) specs for both diff --git a/byron/ledger/executable-spec/src/Ledger/UTxO.hs b/byron/ledger/executable-spec/src/Ledger/UTxO.hs index da567a498fd..e5aa43b139a 100644 --- a/byron/ledger/executable-spec/src/Ledger/UTxO.hs +++ b/byron/ledger/executable-spec/src/Ledger/UTxO.hs @@ -58,7 +58,7 @@ data TxOut = TxOut { addr :: Addr newtype UTxO = UTxO { unUTxO :: Map TxIn TxOut } deriving stock (Show, Data, Typeable) - deriving newtype (Eq, Relation) + deriving newtype (Eq, Relation, Semigroup, Monoid) addValue :: TxOut -> Lovelace -> TxOut addValue tx@TxOut{ value } d = tx { value = value + d } diff --git a/byron/ledger/executable-spec/src/Ledger/Update.hs b/byron/ledger/executable-spec/src/Ledger/Update.hs index f2fbd76a511..25450d3548c 100644 --- a/byron/ledger/executable-spec/src/Ledger/Update.hs +++ b/byron/ledger/executable-spec/src/Ledger/Update.hs @@ -578,6 +578,7 @@ instance STS ADDVOTE where data PredicateFailure ADDVOTE = AVSigDoesNotVerify | NoUpdateProposal UpId + | VoteByNonGenesisDelegate VKey deriving (Eq, Show, Data, Typeable) initialRules = [] @@ -593,6 +594,7 @@ instance STS ADDVOTE where case lookupR vk dms of Just vks -> Set.singleton (pid, vks) Nothing -> Set.empty + vtsPid /= Set.empty ?! VoteByNonGenesisDelegate vk Set.member pid rups ?! NoUpdateProposal pid Core.verify vk pid (vote ^. vSig) ?! AVSigDoesNotVerify return $! vts <> vtsPid @@ -1869,25 +1871,29 @@ mkGoblinGens -- tamperWithUpdateProposal :: UPIEnv -> UPIState -> UProp -> Gen UProp tamperWithUpdateProposal env st uprop = do + -- The frequencies above were determined ad-hoc to get an even coverage in the + -- resulting predicate failures. let failureGenerators - = [ invalidProtocolVersion - , invalidParametersUpdate - , duplicatedProtocolVersion - , duplicatedSoftwareVersion - , invalidSoftwareVersion - , invalidApplicationName - , invalidSystemTag - , invalidIssuer - ] ++ (map (\sg -> sg env st) goblinGensUPIREG) - tamperedUprop <- Gen.choice failureGenerators + = [ (1, invalidProtocolVersion) + , (1, invalidParametersUpdate) + , (5, duplicatedProtocolVersion) + , (5, duplicatedSoftwareVersion) + , (1, invalidSoftwareVersion) + , (1, invalidApplicationName) + , (1, invalidSystemTag) + , (1, invalidIssuer) + ] ++ (map (\sg -> (1, sg env st)) goblinGensUPIREG) + tamperedUprop <- Gen.frequency failureGenerators -- We need to re-sign the update proposal since we changed the contents of - -- 'uprop', however in 1/n of the cases we want to trigger a 'DoesNotVerify' + -- 'uprop', however in 10/n of the cases we want to trigger a 'DoesNotVerify' -- error (where 'n' is the total number of predicate failures, 'n = length - -- failureGenerators + 1'). Thus, in 1/n of the cases we simply return the + -- failureGenerators + 1'). Thus, in 1-/n of the cases we simply return the -- tampered proposal without re-signing it, which will cause the -- 'DoesNotVerify' failure. Gen.frequency [ (length failureGenerators, pure $! reSign tamperedUprop) - , (1, pure $! tamperedUprop) + -- Using 10 in the frequency below will give you us around 15% + -- of proposals with an invalid hash. + , (10, pure $! tamperedUprop) ] where ((_pv, _pps), _fads, _avs, rpus, raus, _cps, _vts, _bvs, _pws) = st diff --git a/byron/ledger/executable-spec/test/Ledger/Core/Generators/Properties.hs b/byron/ledger/executable-spec/test/Ledger/Core/Generators/Properties.hs index 469e5b9036a..d2fa47472ac 100644 --- a/byron/ledger/executable-spec/test/Ledger/Core/Generators/Properties.hs +++ b/byron/ledger/executable-spec/test/Ledger/Core/Generators/Properties.hs @@ -26,19 +26,19 @@ relevantKValuesAreGenerated = withTests 500 $ property $ do epochs :: Word64 epochs = round $ fromIntegral chainLength / (fromIntegral slotsPerEpoch :: Double) - cover 10 + cover 5 "1 epochs " (epochs == 1) - cover 30 + cover 20 "epochs in [2, 25)" (2 <= epochs && epochs < 25) - cover 10 + cover 5 "epochs in [25, 50)" (25 <= epochs && epochs < 50) - cover 10 + cover 5 "50 epochs " (epochs == 50) diff --git a/byron/ledger/executable-spec/test/Ledger/UTxO/Properties.hs b/byron/ledger/executable-spec/test/Ledger/UTxO/Properties.hs index 1c9cae9319b..9c8e7e4b5f4 100644 --- a/byron/ledger/executable-spec/test/Ledger/UTxO/Properties.hs +++ b/byron/ledger/executable-spec/test/Ledger/UTxO/Properties.hs @@ -1,11 +1,12 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} module Ledger.UTxO.Properties where -import Control.Arrow ((***)) +import Control.Arrow (second, (***)) import Control.Lens (view, (&), (^.), _2) import Control.Monad (when) import Data.Foldable (foldl', traverse_) @@ -67,6 +68,16 @@ utxoDiff = withTests 300 . property $ do allTxOuts :: [Tx] -> UTxO allTxOuts txs = foldl' (∪) (UTxO Map.empty) (map txouts txs) +utxoAndTxoutsMustBeDisjoint :: Property +utxoAndTxoutsMustBeDisjoint = withTests 300 . property $ do + t <- forAll (trace @UTXOW 100) + traverse_ utxoAndTxoutsAreDisjoint + $ fmap (second body) + $ preStatesAndSignals OldestFirst t + where + utxoAndTxoutsAreDisjoint (UTxOState {utxo}, tx) = + dom utxo ∩ dom (txouts tx) === mempty + -------------------------------------------------------------------------------- -- Coverage guarantees for UTxO traces -------------------------------------------------------------------------------- diff --git a/byron/ledger/executable-spec/test/Main.hs b/byron/ledger/executable-spec/test/Main.hs index 0e4b1a51ad2..a09dbfbd42c 100644 --- a/byron/ledger/executable-spec/test/Main.hs +++ b/byron/ledger/executable-spec/test/Main.hs @@ -45,6 +45,7 @@ main = defaultMain tests , testProperty "Relevant UTxO traces are generated" UTxO.relevantCasesAreCovered , testProperty "No double spending" UTxO.noDoubleSpending , testProperty "UTxO is outputs minus inputs" UTxO.utxoDiff + , testProperty "UTxO and txouts are disjoint" UTxO.utxoAndTxoutsMustBeDisjoint ] , testTxHasTypeReps , testGroup "Update examples" upiendExamples diff --git a/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/Ledger_Rules.thy b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/Ledger_Rules.thy new file mode 100644 index 00000000000..2f397c67c16 --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/Ledger_Rules.thy @@ -0,0 +1,414 @@ +section \ Proofs \ + +theory Ledger_Rules + imports Main +begin + +text \ Non-standard map operators \ + +definition dom_exc :: "'a set \ ('a \ 'b) \ ('a \ 'b)" ("_ \'/ _" [61, 61] 60) where + "s \/ m = m |` (- s)" + +lemma dom_exc_unit: + assumes "dom m \ s = {}" + shows "s \/ m = m" +proof - + have "s \/ m \\<^sub>m m" + by (simp add: dom_exc_def map_le_def) + moreover from assms have "m \\<^sub>m s \/ m" + by (metis disjoint_eq_subset_Compl dom_exc_def map_le_def restrict_in rev_subsetD) + ultimately show ?thesis + by (simp add: map_le_antisym) +qed + +lemma dom_exc_empty: + shows "{} \/ m = m" + by (simp add: dom_exc_unit) + +lemma dom_exc_union_sec: + shows "(s\<^sub>1 \ s\<^sub>2) \/ m = s\<^sub>1 \/ (s\<^sub>2 \/ m)" + by (simp add: dom_exc_def inf_commute) + +lemma dom_exc_append_distr: + shows "s \/ (m\<^sub>1 ++ m\<^sub>2) = (s \/ m\<^sub>1) ++ (s \/ m\<^sub>2)" +proof - + have ltr: "s \/ (m\<^sub>1 ++ m\<^sub>2) \\<^sub>m (s \/ m\<^sub>1) ++ (s \/ m\<^sub>2)" + by (simp add: dom_exc_def map_add_def map_le_def restrict_map_def) + then have "(s \/ m\<^sub>1) ++ (s \/ m\<^sub>2) \\<^sub>m s \/ (m\<^sub>1 ++ m\<^sub>2)" + by (simp add: dom_exc_def dom_map_add dom_restrict inf_sup_distrib2 map_le_def) + then show ?thesis + by (simp add: ltr map_le_antisym) +qed + +lemma dom_exc_assoc: + assumes "dom m\<^sub>1 \ dom m\<^sub>2 = {}" + and "s \ dom m\<^sub>2 = {}" + shows "(s \/ m\<^sub>1) ++ m\<^sub>2 = s \/ (m\<^sub>1 ++ m\<^sub>2)" +proof - + from assms(1) have "dom (s \/ m\<^sub>1) \ dom m\<^sub>2 = {}" + by (simp add: dom_exc_def inf_commute inf_left_commute) + with assms(2) have rtl: "(s \/ m\<^sub>1) ++ m\<^sub>2 \\<^sub>m s \/ (m\<^sub>1 ++ m\<^sub>2)" + by (smt disjoint_eq_subset_Compl disjoint_iff_not_equal dom_exc_def map_add_dom_app_simps(1) map_add_dom_app_simps(3) map_le_def restrict_map_def subsetCE) + moreover have "s \/ (m\<^sub>1 ++ m\<^sub>2) \\<^sub>m (s \/ m\<^sub>1) ++ m\<^sub>2" + by (smt rtl domIff dom_exc_def map_add_None map_le_def restrict_map_def) + ultimately show ?thesis + using map_le_antisym by blast +qed + +text \ Abstract types \ + +typedecl tx_id +typedecl ix +typedecl addr +typedecl tx + +text \ Derived types \ + +type_synonym coin = int +type_synonym tx_in = "tx_id \ ix" +type_synonym tx_out = "addr \ coin" +type_synonym utxo = "tx_in \ tx_out" + +text \ Transaction Types \ + +type_synonym tx_body = "tx_in set \ (ix \ tx_out)" + +text \ Abstract functions \ + +fun txid :: "tx \ tx_id" where + "txid _ = undefined" + +fun txbody :: "tx \ tx_body" where + "txbody _ = undefined" + +text \ Accessor functions \ + +fun txins :: "tx \ tx_in set" where + "txins tx = (let (inputs, _) = txbody tx in inputs)" + +fun txouts :: "tx \ utxo" where + "txouts tx = ( + let (_, outputs) = txbody tx in ( + \(id, ix). if id \ txid tx then None else case outputs ix of None \ None | Some txout \ Some txout))" + +lemma dom_txouts_is_txid: + shows "\i ix. (i, ix) \ dom (txouts tx) \ i = txid tx" + by (smt case_prod_conv domIff surj_pair txouts.simps) + +text \ UTxO transition-system types \ + +\ \ UTxO environment \ +typedecl utxo_env \ \ Abstract, don't care for now \ + +\ \ UTxO states \ +type_synonym utxo_state = utxo \ \ Simplified \ + +text \ UTxO inference rules \ + +inductive utxo_sts :: "utxo_env \ utxo_state \ tx \ utxo_state \ bool" + ("_ \ _ \\<^bsub>UTXO\<^esub>{_} _" [51, 0, 51] 50) + for \ + where + utxo_inductive: " + \ + txins tx \ dom utxo_st; + txins tx \ {}; + txouts tx \ Map.empty; + \(_, c) \ ran (txouts tx). c > 0 + \ + \ + \ \ utxo_st \\<^bsub>UTXO\<^esub>{tx} (txins tx \/ utxo_st) ++ txouts tx" + +text \ Transaction sequences \ + +inductive utxows :: "utxo_env \ utxo_state \ tx list \ utxo_state \ bool" + ("_ \ _ \\<^bsub>UTXOWS\<^esub>{_} _" [51, 0, 51] 50) + for \ + where + empty: "\ \ s \\<^bsub>UTXOWS\<^esub>{[]} s" | + step: "\ \ s \\<^bsub>UTXOWS\<^esub>{txs @ [tx]} s''" if "\ \ s \\<^bsub>UTXOWS\<^esub>{txs} s'" and "\ \ s' \\<^bsub>UTXO\<^esub>{tx} s''" + +text \ Auxiliary lemmas \ + +abbreviation txid_injectivity :: bool where + "txid_injectivity \ \tx tx'. txid tx = txid tx' \ tx = tx'" + +lemma lemma_1: + assumes "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo" + and "\T\<^sub>i \ set T. txins T\<^sub>i \ txins tx = {}" + and "dom (txouts tx) \ dom utxo\<^sub>0 = {}" + and txid_injectivity + shows "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" + and "dom (txouts tx) \ dom utxo = {}" + using assms +proof (induction rule: utxows.induct) + case (empty s) + { case 1 + then show ?case + by force + next + case 2 + then show ?case + by blast + } +next + case (step utxo\<^sub>0 T utxo tx' utxo') + { case 1 + then have "txins tx' \ dom (txouts tx) = {}" + proof - + from "1.prems"(1) and assms(4) have tx_excl: "\T\<^sub>i \ set T. txins T\<^sub>i \ txins tx = {}" + by auto + with step.IH(1) and "1.prems"(2) and assms(4) + have "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" + by simp + moreover from step.hyps(2) have "txins tx' \ dom utxo" + using utxo_sts.simps by blast + ultimately show ?thesis + by (smt "1.prems"(2) assms(4) tx_excl inf.orderE inf_bot_right inf_sup_aci(1) inf_sup_aci(2) step.IH(2)) + qed + moreover from "1.prems" and step.IH(1) have "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" + by simp + ultimately show ?case + by (smt Int_empty_right SUP_empty UN_Un UN_insert empty_set inf_commute inf_sup_distrib1 list.simps(15) set_append) + next + case 2 + from "2.prems"(1) and assms(4) and step.hyps(2) and step.IH(2) + have "dom (txouts tx) \ dom (txins tx' \/ utxo) = {}" + using utxo_sts.simps by auto + moreover have "dom (txouts tx) \ dom (txouts tx') = {}" + proof - + from "2.prems"(1) have "txins tx' \ txins tx = {}" + by (meson in_set_conv_decomp) + with step.hyps(2) have "txins tx' \ txins tx" + using inf.idem and utxo_sts.cases by auto + then have "tx' \ tx" + by blast + with assms(4) have "txid tx' \ txid tx" + by blast + then show ?thesis + using dom_txouts_is_txid by (simp add: ComplI disjoint_eq_subset_Compl subrelI) + qed + ultimately have "dom (txouts tx) \ dom ((txins tx' \/ utxo) ++ txouts tx') = {}" + by blast + with step.hyps(2) show ?case + using utxo_sts.simps by simp + } +qed + +lemma aux_lemma: + assumes "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo" + and "\ \ utxo \\<^bsub>UTXO\<^esub>{tx} utxo'" + and "\T\<^sub>i \ set (T @ [tx]). dom (txouts T\<^sub>i) \ dom utxo\<^sub>0 = {}" + and "\T\<^sub>i \ set T. dom (txouts T\<^sub>i) \ dom utxo\<^sub>0 = {} \ \T\<^sub>i \ set T. txins T\<^sub>i \ dom utxo = {}" + and txid_injectivity + shows "txins tx \ dom (txouts tx) = {}" +proof - + from assms(2) have "txins tx \ dom utxo" + using utxo_sts.simps by blast + with assms(3,4) have "\T\<^sub>i \ set T. txins T\<^sub>i \ txins tx = {}" + by (smt butlast_snoc in_set_butlastD inf.orderE inf_bot_right inf_left_commute) + with assms(1-3,5) + have "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" and "dom (txouts tx) \ dom utxo = {}" + using lemma_1 by auto + with assms(2) show ?thesis + by (metis (no_types, lifting) disjoint_iff_not_equal subsetCE utxo_sts.simps) +qed + +lemma lemma_3: + assumes "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo" + and "\T\<^sub>i \ set T. dom (txouts T\<^sub>i) \ dom utxo\<^sub>0 = {}" + and txid_injectivity + shows "\T\<^sub>i \ set T. txins T\<^sub>i \ dom utxo = {}" +using assms +proof (induction rule: utxows.induct) + case (empty s) + then show ?case + by simp +next + case (step utxo\<^sub>0 T utxo tx utxo') + then have "\T\<^sub>i. T\<^sub>i \ set T \ txins T\<^sub>i \ dom utxo' = {}" + proof - + fix T\<^sub>i + assume "T\<^sub>i \ set T" + then have "txins T\<^sub>i \ dom (txins tx \/ utxo) = {}" + proof - + from step.IH and \T\<^sub>i \ set T\ and step.prems have "txins T\<^sub>i \ dom utxo = {}" + by (metis butlast_snoc in_set_butlastD) + then show ?thesis + by (simp add: disjoint_iff_not_equal dom_exc_def) + qed + moreover have "txins T\<^sub>i \ dom (txouts tx) = {}" + proof - + from step.hyps(2) have "txins tx \ dom utxo" + using utxo_sts.simps by blast + with step.IH and \T\<^sub>i \ set T\ and step.prems have "\T\<^sub>i \ set T. txins T\<^sub>i \ txins tx = {}" + by (smt butlast_snoc in_set_butlastD inf.orderE inf_bot_right inf_left_commute) + with step.hyps(1) and step.prems have "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" + using lemma_1 in_set_conv_decomp by auto + with \T\<^sub>i \ set T\ show ?thesis + by blast + qed + ultimately have "txins T\<^sub>i \ dom ((txins tx \/ utxo) ++ txouts tx) = {}" + by blast + with step.hyps(2) show "txins T\<^sub>i \ dom utxo' = {}" + using utxo_sts.simps by auto + qed + moreover have "txins tx \ dom utxo' = {}" + proof - + have "txins tx \ dom (txins tx \/ utxo) = {}" + by (simp add: dom_exc_def) + moreover with step.IH and step.hyps(1-2) and step.prems have "txins tx \ dom (txouts tx) = {}" + using aux_lemma by blast + ultimately have "txins tx \ dom ((txins tx \/ utxo) ++ txouts tx) = {}" + by blast + with step.hyps(2) show ?thesis + using utxo_sts.simps by auto + qed + ultimately show ?case + by simp +qed + +subsection \ No Double-Spending Property \ + +theorem no_double_spending: + assumes "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo" + and "\T\<^sub>i \ set T. dom (txouts T\<^sub>i) \ dom utxo\<^sub>0 = {}" + and txid_injectivity + shows "\i \ 0. \j < length T. i < j \ txins (T ! i) \ txins (T ! j) = {}" + using assms +proof (induction arbitrary: utxo rule: utxows.induct) + case (empty s) + then show ?case + by simp +next + case (step utxo\<^sub>0 T utxo tx utxo') + then show ?case + proof (intro allI impI) + fix i j + assume "i \ 0" and "j < length (T @ [tx])" and "i < j" + then consider + (a) "j < length T" | + (b) "j = length T" + by fastforce + then show "txins ((T @ [tx]) ! i) \ txins ((T @ [tx]) ! j) = {}" + proof (cases) + case a + with \i \ 0\ and \i < j\ and step.prems and step.IH show ?thesis + by (smt butlast_snoc in_set_conv_nth length_append_singleton less_Suc_eq less_trans nth_butlast) + next + case b + with \i < j\ have "(T @ [tx]) ! i = T ! i" + by (simp add: nth_append) + moreover with \j = length T\ have "(T @ [tx]) ! j = tx" + by simp + ultimately have "txins (T ! i) \ txins tx = {}" + proof - + have "txins (T ! i) \ dom utxo = {}" + using lemma_3 \\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo\ \i < j\ b step.prems + by (metis UnCI nth_mem set_append) + moreover from \\ \ utxo \\<^bsub>UTXO\<^esub>{tx} utxo'\ and utxo_sts.simps have "txins tx \ dom utxo" + by simp + ultimately show ?thesis by blast + qed + with \(T @ [tx]) ! j = tx\ and \(T @ [tx]) ! i = T ! i\ show ?thesis + by simp + qed + qed +qed + +subsection \ UTxO Difference Property \ + +primrec general_append :: "['a \ ('b \ 'c), 'a list] \ ('b \ 'c)" where + "general_append _ [] = Map.empty" | + "general_append f (x # xs) = f x ++ general_append f xs" + +syntax + "_general_append" :: "pttrn => 'a list => 'b \ 'c => 'b \ 'c" ("(3\_\_. _)" [0, 0, 100] 100) +translations + "\x\xs. p" \ "CONST general_append (\x. p) xs" + +lemma general_append_rev: + shows "(\x\(xs @ [y]). P x) = (\x\xs. P x) ++ P y" + by (induction xs) simp_all + +theorem utxo_is_outputs_minus_inputs: + assumes "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{T} utxo" + and "\T\<^sub>i \ set T. dom (txouts T\<^sub>i) \ dom utxo\<^sub>0 = {}" + and txid_injectivity + shows "(\T\<^sub>i \ set T. txins T\<^sub>i) \/ (utxo\<^sub>0 ++ (\T\<^sub>i\T. txouts T\<^sub>i)) = utxo" + using assms +proof (induction rule: utxows.induct) + case (empty s) + then show ?case + by (simp add: dom_exc_empty) +next + case (step utxo\<^sub>0 T utxo tx utxo') + let ?T' = "T @ [tx]" + from step.hyps(1,2) have "\ \ utxo\<^sub>0 \\<^bsub>UTXOWS\<^esub>{?T'} utxo'" + by (simp add: utxows.step) + with step.prems(1,2) + have "\i \ 0. \j < length ?T'. i < j \ txins (?T' ! i) \ txins (?T' ! j) = {}" + using no_double_spending by simp + with step.hyps(2) have *: "\T\<^sub>i \ set T. txins T\<^sub>i \ txins tx = {}" + using subsetCE and utxo_sts.simps by auto + have PO\<^sub>0: "(\T\<^sub>i \ set T. txins T\<^sub>i) \/ txouts tx = txouts tx" + proof - + from * and step.hyps(1) and step.prems(1,2) + have "(\T\<^sub>i \ set T. txins T\<^sub>i) \ dom (txouts tx) = {}" + using lemma_1(1) by auto + with * show ?thesis + using dom_exc_empty by auto + qed + have PO\<^sub>1: "txins tx \/ txouts tx = txouts tx" + proof - + from * and step.hyps(1) and step.prems(1,2) + have "dom (txouts tx) \ dom utxo = {}" + using lemma_1(2) by simp + moreover from step.hyps(2) have "txins tx \ dom utxo" + using utxo_sts.simps by blast + ultimately have "dom (txouts tx) \ txins tx = {}" + by blast + then show ?thesis + by (simp add: dom_exc_unit) + qed + have " + (\T\<^sub>i \ set (T @ [tx]). txins T\<^sub>i) \/ (utxo\<^sub>0 ++ (\T\<^sub>i\(T @ [tx]). txouts T\<^sub>i)) + = + (txins tx \ (\T\<^sub>i \ set T. txins T\<^sub>i)) \/ (utxo\<^sub>0 ++ (\T\<^sub>i\(T @ [tx]). txouts T\<^sub>i))" + by simp + also have " + \ + = + txins tx \/ ((\T\<^sub>i \ set T. txins T\<^sub>i) \/ ((utxo\<^sub>0 ++ (\T\<^sub>i\T. txouts T\<^sub>i)) ++ txouts tx))" + by (simp add: dom_exc_union_sec general_append_rev) + also have " + \ + = + txins tx \/ + ( + ((\T\<^sub>i \ set T. txins T\<^sub>i) \/ (utxo\<^sub>0 ++ (\T\<^sub>i\T. txouts T\<^sub>i))) + ++ + ((\T\<^sub>i \ set T. txins T\<^sub>i) \/ txouts tx) + )" + by (simp add: dom_exc_append_distr) + also from step.IH and step.prems(1,2) have " + \ + = + txins tx \/ + ( + utxo + ++ + ((\T\<^sub>i \ set T. txins T\<^sub>i) \/ txouts tx) + )" + by simp + also from PO\<^sub>0 have "\ = txins tx \/ (utxo ++ txouts tx)" + by simp + also have "\ = (txins tx \/ utxo) ++ (txins tx \/ txouts tx)" + by (simp add: dom_exc_append_distr) + also from PO\<^sub>1 have "\ = (txins tx \/ utxo) ++ txouts tx" + by simp + finally show ?case + using step.hyps(2) and utxo_sts.simps by simp +qed + +end diff --git a/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/ROOT b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/ROOT new file mode 100644 index 00000000000..a0cea30f74c --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/ROOT @@ -0,0 +1,8 @@ +chapter Ledger_Rules + +session Ledger_Rules_Formalization(ledgerrules) = HOL + + description \Formalization of Ledger Rules in Isabelle/HOL\ + theories + Ledger_Rules + document_files + "root.tex" diff --git a/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/document/root.tex b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/document/root.tex new file mode 100644 index 00000000000..3132cadf05b --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/Ledger_Rules_Formalization/document/root.tex @@ -0,0 +1,31 @@ +\documentclass[a4paper,11pt]{article} + +\usepackage{typearea} + +\usepackage{lmodern} +\usepackage[T1]{fontenc} +\usepackage{textcomp} + +\usepackage{isabelle,isabellesym} + +\usepackage{latexsym} + +\usepackage{pdfsetup} + +\urlstyle{rm} +\isabellestyle{it} + +\begin{document} + +\title{Formalization of the Ledger Rules in Isabelle/HOL} +\author{Javier D\'iaz\\\small\texttt{javier.diaz@iohk.io}\\\small\texttt{github.com/input-output-hk/fm-ouroboros}} + +\maketitle + +\tableofcontents + +\parindent 0pt\parskip 0.5ex + +\input{session} + +\end{document} diff --git a/byron/ledger/formal-spec/Isabelle/Makefile b/byron/ledger/formal-spec/Isabelle/Makefile new file mode 100644 index 00000000000..30a020af6e4 --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/Makefile @@ -0,0 +1,7 @@ +build_options = -o document=pdf -g ledgerrules + +properly: + isabelle build $(build_options) + +qnd: + isabelle build -o quick_and_dirty $(build_options) diff --git a/byron/ledger/formal-spec/Isabelle/README.md b/byron/ledger/formal-spec/Isabelle/README.md new file mode 100644 index 00000000000..6d7f2d638a9 --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/README.md @@ -0,0 +1,37 @@ +Requirements +============ + +You need Isabelle2018 to use the Isabelle developments in this +directory. You can obtain Isabelle2018 from the [Isabelle +website][isabelle]. + +[isabelle]: + http://isabelle.in.tum.de/ + "Isabelle" + + +Setup +===== + +To make the Isabelle developments in this directory available to your +Isabelle installation, please add the path of this directory to the file +`$ISABELLE_HOME_USER/ROOTS`. You can find out the value of +`$ISABELLE_HOME_USER` by running the following command: + + isabelle getenv ISABELLE_HOME_USER + + +Building +======== + +Running `make` builds the PDF documents for the different Isabelle +libraries and places them in `$ISABELLE_BROWSER_INFO/Ledger_Rules`. You can +find out the value of `$ISABELLE_BROWSER_INFO` by running the following +command: + + isabelle getenv ISABELLE_BROWSER_INFO + +The makefile specifies two targets: `properly`, which is the default, +and `qnd`. With `properly`, fake proofs (`sorry`) are not accepted; with +`qnd`, quick-and-dirty mode is used and thus fake proofs are accepted. + diff --git a/byron/ledger/formal-spec/Isabelle/ROOTS b/byron/ledger/formal-spec/Isabelle/ROOTS new file mode 100644 index 00000000000..8901ffa535f --- /dev/null +++ b/byron/ledger/formal-spec/Isabelle/ROOTS @@ -0,0 +1 @@ +Ledger_Rules_Formalization \ No newline at end of file diff --git a/byron/semantics/executable-spec/src/Control/State/Transition/Generator.hs b/byron/semantics/executable-spec/src/Control/State/Transition/Generator.hs index c53b126c775..a2652424455 100644 --- a/byron/semantics/executable-spec/src/Control/State/Transition/Generator.hs +++ b/byron/semantics/executable-spec/src/Control/State/Transition/Generator.hs @@ -53,6 +53,7 @@ module Control.State.Transition.Generator -- * Trace properties , traceLengthsAreClassified , onlyValidSignalsAreGenerated + , onlyValidSignalsAreGeneratedForTrace , invalidSignalsAreGenerated -- * Helpers , tinkerWithSigGen @@ -92,7 +93,6 @@ import qualified Hedgehog.Extra.Manual as Manual import Test.Goblin (Goblin (..), GoblinData, SeedGoblin (..)) - class STS s => HasTrace s where -- | Generate an initial environment that is based on the given trace length. envGen @@ -602,8 +602,17 @@ onlyValidSignalsAreGenerated => Word64 -- ^ Maximum trace length. -> Property -onlyValidSignalsAreGenerated maximumTraceLength = property $ do - tr <- forAll (trace @s maximumTraceLength) +onlyValidSignalsAreGenerated maximumTraceLength = + onlyValidSignalsAreGeneratedForTrace (trace @s maximumTraceLength) + +-- | Check that the signal generator of 's' only generate valid signals. +onlyValidSignalsAreGeneratedForTrace + :: forall s + . (HasTrace s, Show (Environment s), Show (State s), Show (Signal s), HasCallStack) + => Gen (Trace s) + -> Property +onlyValidSignalsAreGeneratedForTrace traceGen = property $ do + tr <- forAll traceGen let env :: Environment s env = _traceEnv tr @@ -619,7 +628,6 @@ onlyValidSignalsAreGenerated maximumTraceLength = property $ do footnoteShow result void $ evalEither result - coverFailures :: forall m s a . ( MonadTest m diff --git a/cabal.project b/cabal.project index 7c537aebd42..7ec360cbfe4 100644 --- a/cabal.project +++ b/cabal.project @@ -12,19 +12,19 @@ constraints: source-repository-package type: git location: https://github.com/input-output-hk/cardano-base - tag: bb262f466d659d94ed6e5500c2dc101f7c2c6b1e + tag: 5c575d46afbfe333de0ccba70b084db8302abf42 subdir: binary source-repository-package type: git location: https://github.com/input-output-hk/cardano-base - tag: bb262f466d659d94ed6e5500c2dc101f7c2c6b1e + tag: 5c575d46afbfe333de0ccba70b084db8302abf42 subdir: cardano-crypto-class source-repository-package type: git location: https://github.com/input-output-hk/cardano-prelude - tag: b9bf62f2bab90539809bee13620fe7d29b35928d + tag: f12a60595dbc2436d99a198b717bf26a683b5eec source-repository-package type: git diff --git a/nix/.stack.nix/cardano-binary.nix b/nix/.stack.nix/cardano-binary.nix index 183256ad1c2..1e2478736a3 100644 --- a/nix/.stack.nix/cardano-binary.nix +++ b/nix/.stack.nix/cardano-binary.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,54 +52,57 @@ synopsis = "Binary serialization for Cardano"; description = "This package includes the binary serialization format for Cardano"; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.aeson) - (hsPkgs.bytestring) - (hsPkgs.cardano-prelude) - (hsPkgs.cborg) - (hsPkgs.containers) - (hsPkgs.digest) - (hsPkgs.formatting) - (hsPkgs.recursion-schemes) - (hsPkgs.safe-exceptions) - (hsPkgs.tagged) - (hsPkgs.text) - (hsPkgs.time) - (hsPkgs.vector) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."aeson" or (buildDepError "aeson")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) + (hsPkgs."cborg" or (buildDepError "cborg")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."digest" or (buildDepError "digest")) + (hsPkgs."formatting" or (buildDepError "formatting")) + (hsPkgs."recursion-schemes" or (buildDepError "recursion-schemes")) + (hsPkgs."safe-exceptions" or (buildDepError "safe-exceptions")) + (hsPkgs."tagged" or (buildDepError "tagged")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."time" or (buildDepError "time")) + (hsPkgs."vector" or (buildDepError "vector")) ]; + buildable = true; }; tests = { "test" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.cardano-binary) - (hsPkgs.cardano-prelude) - (hsPkgs.cardano-prelude-test) - (hsPkgs.cborg) - (hsPkgs.containers) - (hsPkgs.formatting) - (hsPkgs.hedgehog) - (hsPkgs.hspec) - (hsPkgs.pretty-show) - (hsPkgs.QuickCheck) - (hsPkgs.quickcheck-instances) - (hsPkgs.tagged) - (hsPkgs.text) - (hsPkgs.vector) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) + (hsPkgs."cardano-prelude-test" or (buildDepError "cardano-prelude-test")) + (hsPkgs."cborg" or (buildDepError "cborg")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."formatting" or (buildDepError "formatting")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."hspec" or (buildDepError "hspec")) + (hsPkgs."pretty-show" or (buildDepError "pretty-show")) + (hsPkgs."QuickCheck" or (buildDepError "QuickCheck")) + (hsPkgs."quickcheck-instances" or (buildDepError "quickcheck-instances")) + (hsPkgs."tagged" or (buildDepError "tagged")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."vector" or (buildDepError "vector")) ]; + buildable = true; }; }; }; } // { src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-base"; - rev = "bb262f466d659d94ed6e5500c2dc101f7c2c6b1e"; - sha256 = "1vmp4lia4s2c20wgfbyvywsdmzg0s1m25zjw7n8a0my7cjg7n3vg"; + rev = "5c575d46afbfe333de0ccba70b084db8302abf42"; + sha256 = "1v1q20fjb6klcdhl9mhpvd10j6vc7biwk91dgyfp6ld7xvj2703x"; }); postUnpack = "sourceRoot+=/binary; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-crypto-class.nix b/nix/.stack.nix/cardano-crypto-class.nix index dc60b70778a..9607858ec8e 100644 --- a/nix/.stack.nix/cardano-crypto-class.nix +++ b/nix/.stack.nix/cardano-crypto-class.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,43 +52,46 @@ synopsis = "Type classes abstracting over cryptography primitives for Cardano"; description = "Type classes abstracting over cryptography primitives for Cardano"; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.base16-bytestring) - (hsPkgs.bytestring) - (hsPkgs.cardano-binary) - (hsPkgs.cardano-prelude) - (hsPkgs.cryptonite) - (hsPkgs.deepseq) - (hsPkgs.memory) - (hsPkgs.reflection) - (hsPkgs.vector) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."base16-bytestring" or (buildDepError "base16-bytestring")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."deepseq" or (buildDepError "deepseq")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."reflection" or (buildDepError "reflection")) + (hsPkgs."vector" or (buildDepError "vector")) ]; + buildable = true; }; tests = { "test-crypto" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.cardano-binary) - (hsPkgs.cardano-crypto-class) - (hsPkgs.cborg) - (hsPkgs.cryptonite) - (hsPkgs.QuickCheck) - (hsPkgs.tasty) - (hsPkgs.tasty-quickcheck) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."cardano-crypto-class" or (buildDepError "cardano-crypto-class")) + (hsPkgs."cborg" or (buildDepError "cborg")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."QuickCheck" or (buildDepError "QuickCheck")) + (hsPkgs."tasty" or (buildDepError "tasty")) + (hsPkgs."tasty-quickcheck" or (buildDepError "tasty-quickcheck")) ]; + buildable = true; }; }; }; } // { src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-base"; - rev = "bb262f466d659d94ed6e5500c2dc101f7c2c6b1e"; - sha256 = "1vmp4lia4s2c20wgfbyvywsdmzg0s1m25zjw7n8a0my7cjg7n3vg"; + rev = "5c575d46afbfe333de0ccba70b084db8302abf42"; + sha256 = "1v1q20fjb6klcdhl9mhpvd10j6vc7biwk91dgyfp6ld7xvj2703x"; }); postUnpack = "sourceRoot+=/cardano-crypto-class; echo source root reset to \$sourceRoot"; } \ No newline at end of file diff --git a/nix/.stack.nix/cardano-crypto.nix b/nix/.stack.nix/cardano-crypto.nix index 30bdba93a5c..3bec2211096 100644 --- a/nix/.stack.nix/cardano-crypto.nix +++ b/nix/.stack.nix/cardano-crypto.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { golden-tests = false; golden-tests-exe = false; }; package = { @@ -13,69 +52,75 @@ synopsis = "Cryptography primitives for cardano"; description = ""; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.memory) - (hsPkgs.deepseq) - (hsPkgs.bytestring) - (hsPkgs.basement) - (hsPkgs.foundation) - (hsPkgs.cryptonite) - (hsPkgs.cryptonite-openssl) - (hsPkgs.hashable) - (hsPkgs.integer-gmp) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."deepseq" or (buildDepError "deepseq")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."basement" or (buildDepError "basement")) + (hsPkgs."foundation" or (buildDepError "foundation")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."cryptonite-openssl" or (buildDepError "cryptonite-openssl")) + (hsPkgs."hashable" or (buildDepError "hashable")) + (hsPkgs."integer-gmp" or (buildDepError "integer-gmp")) ]; + buildable = true; }; exes = { "golden-tests" = { depends = [ - (hsPkgs.base) - (hsPkgs.basement) - (hsPkgs.foundation) - (hsPkgs.memory) - (hsPkgs.bytestring) - (hsPkgs.cryptonite) - (hsPkgs.cardano-crypto) - ] ++ (pkgs.lib).optional (flags.golden-tests-exe) (hsPkgs.inspector); + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."basement" or (buildDepError "basement")) + (hsPkgs."foundation" or (buildDepError "foundation")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."cardano-crypto" or (buildDepError "cardano-crypto")) + ] ++ (pkgs.lib).optional (flags.golden-tests-exe) (hsPkgs."inspector" or (buildDepError "inspector")); + buildable = if flags.golden-tests-exe then true else false; }; }; tests = { "cardano-crypto-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.memory) - (hsPkgs.cryptonite) - (hsPkgs.cardano-crypto) - (hsPkgs.basement) - (hsPkgs.foundation) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."cardano-crypto" or (buildDepError "cardano-crypto")) + (hsPkgs."basement" or (buildDepError "basement")) + (hsPkgs."foundation" or (buildDepError "foundation")) ]; + buildable = true; }; "cardano-crypto-golden-tests" = { depends = [ - (hsPkgs.base) - (hsPkgs.basement) - (hsPkgs.foundation) - (hsPkgs.memory) - (hsPkgs.bytestring) - (hsPkgs.cryptonite) - (hsPkgs.cardano-crypto) - ] ++ (pkgs.lib).optional (flags.golden-tests) (hsPkgs.inspector); + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."basement" or (buildDepError "basement")) + (hsPkgs."foundation" or (buildDepError "foundation")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."cardano-crypto" or (buildDepError "cardano-crypto")) + ] ++ (pkgs.lib).optional (flags.golden-tests) (hsPkgs."inspector" or (buildDepError "inspector")); + buildable = if flags.golden-tests then true else false; }; }; benchmarks = { "cardano-crypto-bench" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.memory) - (hsPkgs.cryptonite) - (hsPkgs.cardano-crypto) - (hsPkgs.gauge) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."cardano-crypto" or (buildDepError "cardano-crypto")) + (hsPkgs."gauge" or (buildDepError "gauge")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/cardano-prelude.nix b/nix/.stack.nix/cardano-prelude.nix index ae116e44193..114fd3133ed 100644 --- a/nix/.stack.nix/cardano-prelude.nix +++ b/nix/.stack.nix/cardano-prelude.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,65 +52,68 @@ synopsis = "A Prelude replacement for the Cardano project"; description = "A Prelude replacement for the Cardano project"; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.aeson) - (hsPkgs.array) - (hsPkgs.base16-bytestring) - (hsPkgs.bytestring) - (hsPkgs.canonical-json) - (hsPkgs.cborg) - (hsPkgs.containers) - (hsPkgs.formatting) - (hsPkgs.ghc-heap) - (hsPkgs.ghc-prim) - (hsPkgs.hashable) - (hsPkgs.integer-gmp) - (hsPkgs.mtl) - (hsPkgs.nonempty-containers) - (hsPkgs.protolude) - (hsPkgs.tagged) - (hsPkgs.text) - (hsPkgs.time) - (hsPkgs.vector) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."aeson" or (buildDepError "aeson")) + (hsPkgs."array" or (buildDepError "array")) + (hsPkgs."base16-bytestring" or (buildDepError "base16-bytestring")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."canonical-json" or (buildDepError "canonical-json")) + (hsPkgs."cborg" or (buildDepError "cborg")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."formatting" or (buildDepError "formatting")) + (hsPkgs."ghc-heap" or (buildDepError "ghc-heap")) + (hsPkgs."ghc-prim" or (buildDepError "ghc-prim")) + (hsPkgs."hashable" or (buildDepError "hashable")) + (hsPkgs."integer-gmp" or (buildDepError "integer-gmp")) + (hsPkgs."mtl" or (buildDepError "mtl")) + (hsPkgs."nonempty-containers" or (buildDepError "nonempty-containers")) + (hsPkgs."protolude" or (buildDepError "protolude")) + (hsPkgs."tagged" or (buildDepError "tagged")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."time" or (buildDepError "time")) + (hsPkgs."vector" or (buildDepError "vector")) ]; + buildable = true; }; tests = { "cardano-prelude-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.aeson) - (hsPkgs.aeson-pretty) - (hsPkgs.attoparsec) - (hsPkgs.base16-bytestring) - (hsPkgs.bytestring) - (hsPkgs.canonical-json) - (hsPkgs.cardano-prelude) - (hsPkgs.containers) - (hsPkgs.cryptonite) - (hsPkgs.formatting) - (hsPkgs.ghc-heap) - (hsPkgs.ghc-prim) - (hsPkgs.hedgehog) - (hsPkgs.hspec) - (hsPkgs.pretty-show) - (hsPkgs.QuickCheck) - (hsPkgs.quickcheck-instances) - (hsPkgs.random) - (hsPkgs.text) - (hsPkgs.template-haskell) - (hsPkgs.time) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."aeson" or (buildDepError "aeson")) + (hsPkgs."aeson-pretty" or (buildDepError "aeson-pretty")) + (hsPkgs."attoparsec" or (buildDepError "attoparsec")) + (hsPkgs."base16-bytestring" or (buildDepError "base16-bytestring")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."canonical-json" or (buildDepError "canonical-json")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."formatting" or (buildDepError "formatting")) + (hsPkgs."ghc-heap" or (buildDepError "ghc-heap")) + (hsPkgs."ghc-prim" or (buildDepError "ghc-prim")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."hspec" or (buildDepError "hspec")) + (hsPkgs."pretty-show" or (buildDepError "pretty-show")) + (hsPkgs."QuickCheck" or (buildDepError "QuickCheck")) + (hsPkgs."quickcheck-instances" or (buildDepError "quickcheck-instances")) + (hsPkgs."random" or (buildDepError "random")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."template-haskell" or (buildDepError "template-haskell")) + (hsPkgs."time" or (buildDepError "time")) ]; + buildable = true; }; }; }; } // { src = (pkgs.lib).mkDefault (pkgs.fetchgit { url = "https://github.com/input-output-hk/cardano-prelude"; - rev = "b9bf62f2bab90539809bee13620fe7d29b35928d"; - sha256 = "0fzk6z3dgnz5wrj7zp3gxzrf11hcik22ibp5z4i8d7d7hg0ngs9h"; + rev = "f12a60595dbc2436d99a198b717bf26a683b5eec"; + sha256 = "06z4wnwz1jnpwh77a8gb6y8yvnrr2a7wip5rj39aw4pksxk339js"; }); } \ No newline at end of file diff --git a/nix/.stack.nix/cs-blockchain.nix b/nix/.stack.nix/cs-blockchain.nix index 5b066d4b37d..d2a60af07ba 100644 --- a/nix/.stack.nix/cs-blockchain.nix +++ b/nix/.stack.nix/cs-blockchain.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,37 +52,40 @@ synopsis = "Executable specification of the Cardano blockchain"; description = ""; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.bimap) - (hsPkgs.bytestring) - (hsPkgs.containers) - (hsPkgs.cs-ledger) - (hsPkgs.goblins) - (hsPkgs.hashable) - (hsPkgs.hedgehog) - (hsPkgs.lens) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bimap" or (buildDepError "bimap")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) + (hsPkgs."goblins" or (buildDepError "goblins")) + (hsPkgs."hashable" or (buildDepError "hashable")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; tests = { "chain-rules-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.containers) - (hsPkgs.data-ordlist) - (hsPkgs.hedgehog) - (hsPkgs.lens) - (hsPkgs.tasty) - (hsPkgs.tasty-hedgehog) - (hsPkgs.tasty-hunit) - (hsPkgs.cs-blockchain) - (hsPkgs.cs-ledger) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."data-ordlist" or (buildDepError "data-ordlist")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."tasty" or (buildDepError "tasty")) + (hsPkgs."tasty-hedgehog" or (buildDepError "tasty-hedgehog")) + (hsPkgs."tasty-hunit" or (buildDepError "tasty-hunit")) + (hsPkgs."cs-blockchain" or (buildDepError "cs-blockchain")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/cs-ledger.nix b/nix/.stack.nix/cs-ledger.nix index ad760f87aa5..de7a5ebc2ab 100644 --- a/nix/.stack.nix/cs-ledger.nix +++ b/nix/.stack.nix/cs-ledger.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,56 +52,60 @@ synopsis = "Executable specification of Cardano ledger"; description = ""; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.bimap) - (hsPkgs.containers) - (hsPkgs.filepath) - (hsPkgs.file-embed) - (hsPkgs.goblins) - (hsPkgs.hashable) - (hsPkgs.hedgehog) - (hsPkgs.lens) - (hsPkgs.template-haskell) - (hsPkgs.Unique) - (hsPkgs.cardano-binary) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bimap" or (buildDepError "bimap")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."filepath" or (buildDepError "filepath")) + (hsPkgs."file-embed" or (buildDepError "file-embed")) + (hsPkgs."goblins" or (buildDepError "goblins")) + (hsPkgs."hashable" or (buildDepError "hashable")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."template-haskell" or (buildDepError "template-haskell")) + (hsPkgs."Unique" or (buildDepError "Unique")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; tests = { "doctests" = { depends = [ - (hsPkgs.base) - (hsPkgs.doctest) - (hsPkgs.containers) - (hsPkgs.hedgehog) - (hsPkgs.lens) - (hsPkgs.memory) - (hsPkgs.text) - (hsPkgs.small-steps) - (hsPkgs.cs-ledger) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."doctest" or (buildDepError "doctest")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."memory" or (buildDepError "memory")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) ]; build-tools = [ - (hsPkgs.buildPackages.doctest-discover or (pkgs.buildPackages.doctest-discover)) + (hsPkgs.buildPackages.doctest-discover or (pkgs.buildPackages.doctest-discover or (buildToolDepError "doctest-discover"))) ]; + buildable = true; }; "ledger-rules-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.bimap) - (hsPkgs.containers) - (hsPkgs.lens) - (hsPkgs.hedgehog) - (hsPkgs.tasty) - (hsPkgs.tasty-hunit) - (hsPkgs.tasty-hedgehog) - (hsPkgs.Unique) - (hsPkgs.cs-ledger) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bimap" or (buildDepError "bimap")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."tasty" or (buildDepError "tasty")) + (hsPkgs."tasty-hunit" or (buildDepError "tasty-hunit")) + (hsPkgs."tasty-hedgehog" or (buildDepError "tasty-hedgehog")) + (hsPkgs."Unique" or (buildDepError "Unique")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/default.nix b/nix/.stack.nix/default.nix index b2e91974ef5..abb2681ec52 100644 --- a/nix/.stack.nix/default.nix +++ b/nix/.stack.nix/default.nix @@ -11,10 +11,10 @@ "base58-bytestring" = (((hackage.base58-bytestring)."0.1.0").revisions).default; "hedgehog" = (((hackage.hedgehog)."1.0").revisions).default; "micro-recursion-schemes" = (((hackage.micro-recursion-schemes)."5.0.2.2").revisions).default; + "protolude" = (((hackage.protolude)."0.2.4").revisions).default; "streaming-binary" = (((hackage.streaming-binary)."0.3.0.1").revisions).default; "cborg" = (((hackage.cborg)."0.2.2.0").revisions).default; "canonical-json" = (((hackage.canonical-json)."0.6.0.0").revisions).default; - } // { delegation = ./delegation.nix; cs-blockchain = ./cs-blockchain.nix; cs-ledger = ./cs-ledger.nix; @@ -30,5 +30,6 @@ compiler.nix-name = "ghc865"; }; resolver = "lts-13.26"; + modules = [ ({ lib, ... }: { packages = {}; }) { packages = {}; } ]; compiler = "ghc-8.6.5"; } \ No newline at end of file diff --git a/nix/.stack.nix/delegation.nix b/nix/.stack.nix/delegation.nix index ae0ef938187..9e1a7b4168d 100644 --- a/nix/.stack.nix/delegation.nix +++ b/nix/.stack.nix/delegation.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,46 +52,49 @@ synopsis = ""; description = "Delegation Executable Model"; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.containers) - (hsPkgs.cryptonite) - (hsPkgs.hedgehog) - (hsPkgs.small-steps) - (hsPkgs.microlens) - (hsPkgs.microlens-th) - (hsPkgs.non-integer) - (hsPkgs.cs-ledger) - (hsPkgs.cardano-binary) - (hsPkgs.cardano-crypto-class) - (hsPkgs.cardano-prelude) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) + (hsPkgs."microlens" or (buildDepError "microlens")) + (hsPkgs."microlens-th" or (buildDepError "microlens-th")) + (hsPkgs."non-integer" or (buildDepError "non-integer")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."cardano-crypto-class" or (buildDepError "cardano-crypto-class")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) ]; + buildable = true; }; tests = { "delegation-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.bytestring) - (hsPkgs.cryptonite) - (hsPkgs.tasty) - (hsPkgs.tasty-hunit) - (hsPkgs.tasty-hedgehog) - (hsPkgs.hedgehog) - (hsPkgs.delegation) - (hsPkgs.containers) - (hsPkgs.multiset) - (hsPkgs.text) - (hsPkgs.microlens) - (hsPkgs.cs-ledger) - (hsPkgs.cardano-binary) - (hsPkgs.cardano-crypto-class) - (hsPkgs.cardano-prelude) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."tasty" or (buildDepError "tasty")) + (hsPkgs."tasty-hunit" or (buildDepError "tasty-hunit")) + (hsPkgs."tasty-hedgehog" or (buildDepError "tasty-hedgehog")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."delegation" or (buildDepError "delegation")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."multiset" or (buildDepError "multiset")) + (hsPkgs."text" or (buildDepError "text")) + (hsPkgs."microlens" or (buildDepError "microlens")) + (hsPkgs."cs-ledger" or (buildDepError "cs-ledger")) + (hsPkgs."cardano-binary" or (buildDepError "cardano-binary")) + (hsPkgs."cardano-crypto-class" or (buildDepError "cardano-crypto-class")) + (hsPkgs."cardano-prelude" or (buildDepError "cardano-prelude")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/goblins.nix b/nix/.stack.nix/goblins.nix index 9ef4915b369..64fd887e5b1 100644 --- a/nix/.stack.nix/goblins.nix +++ b/nix/.stack.nix/goblins.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,37 +52,40 @@ synopsis = "Genetic algorithm based randomised testing"; description = ""; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.bimap) - (hsPkgs.binary) - (hsPkgs.bytestring) - (hsPkgs.containers) - (hsPkgs.extra) - (hsPkgs.hedgehog) - (hsPkgs.lens) - (hsPkgs.mmorph) - (hsPkgs.monad-control) - (hsPkgs.moo) - (hsPkgs.random) - (hsPkgs.template-haskell) - (hsPkgs.th-utilities) - (hsPkgs.transformers) - (hsPkgs.tree-diff) - (hsPkgs.typerep-map) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."bimap" or (buildDepError "bimap")) + (hsPkgs."binary" or (buildDepError "binary")) + (hsPkgs."bytestring" or (buildDepError "bytestring")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."extra" or (buildDepError "extra")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."mmorph" or (buildDepError "mmorph")) + (hsPkgs."monad-control" or (buildDepError "monad-control")) + (hsPkgs."moo" or (buildDepError "moo")) + (hsPkgs."random" or (buildDepError "random")) + (hsPkgs."template-haskell" or (buildDepError "template-haskell")) + (hsPkgs."th-utilities" or (buildDepError "th-utilities")) + (hsPkgs."transformers" or (buildDepError "transformers")) + (hsPkgs."tree-diff" or (buildDepError "tree-diff")) + (hsPkgs."typerep-map" or (buildDepError "typerep-map")) ]; + buildable = true; }; tests = { "goblin-test" = { depends = [ - (hsPkgs.base) - (hsPkgs.hedgehog) - (hsPkgs.goblins) - (hsPkgs.temporary) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."goblins" or (buildDepError "goblins")) + (hsPkgs."temporary" or (buildDepError "temporary")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/non-integer.nix b/nix/.stack.nix/non-integer.nix index 2cfbfeb7173..6d0e2b416d2 100644 --- a/nix/.stack.nix/non-integer.nix +++ b/nix/.stack.nix/non-integer.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,19 +52,30 @@ synopsis = ""; description = "Implementation decision for non-integer calculations"; buildType = "Simple"; + isLocal = true; }; components = { - "library" = { depends = [ (hsPkgs.base) ]; }; + "library" = { + depends = [ (hsPkgs."base" or (buildDepError "base")) ]; + buildable = true; + }; exes = { - "nonInt" = { depends = [ (hsPkgs.base) (hsPkgs.non-integer) ]; }; + "nonInt" = { + depends = [ + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."non-integer" or (buildDepError "non-integer")) + ]; + buildable = true; + }; }; tests = { "non-integer-test" = { depends = (pkgs.lib).optionals (!flags.development) [ - (hsPkgs.base) - (hsPkgs.non-integer) - (hsPkgs.QuickCheck) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."non-integer" or (buildDepError "non-integer")) + (hsPkgs."QuickCheck" or (buildDepError "QuickCheck")) ]; + buildable = true; }; }; }; diff --git a/nix/.stack.nix/small-steps.nix b/nix/.stack.nix/small-steps.nix index d6eb5cdb79d..e286aacd6d3 100644 --- a/nix/.stack.nix/small-steps.nix +++ b/nix/.stack.nix/small-steps.nix @@ -1,4 +1,43 @@ -{ system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: +let + buildDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (build dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + sysDepError = pkg: + builtins.throw '' + The Nixpkgs package set does not contain the package: ${pkg} (system dependency). + + You may need to augment the system package mapping in haskell.nix so that it can be found. + ''; + pkgConfDepError = pkg: + builtins.throw '' + The pkg-conf packages does not contain the package: ${pkg} (pkg-conf dependency). + + You may need to augment the pkg-conf package mapping in haskell.nix so that it can be found. + ''; + exeDepError = pkg: + builtins.throw '' + The local executable components do not include the component: ${pkg} (executable dependency). + ''; + legacyExeDepError = pkg: + builtins.throw '' + The Haskell package set does not contain the package: ${pkg} (executable dependency). + + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; + buildToolDepError = pkg: + builtins.throw '' + Neither the Haskell package set or the Nixpkgs package set contain the package: ${pkg} (build tool dependency). + + If this is a system dependency: + You may need to augment the system package mapping in haskell.nix so that it can be found. + + If this is a Haskell dependency: + If you are using Stackage, make sure that you are using a snapshot that contains the package. Otherwise you may need to update the Hackage snapshot you are using, usually by updating haskell.nix. + ''; +in { system, compiler, flags, pkgs, hsPkgs, pkgconfPkgs, ... }: { flags = { development = false; }; package = { @@ -13,53 +52,57 @@ synopsis = "Small step semantics"; description = ""; buildType = "Simple"; + isLocal = true; }; components = { "library" = { depends = [ - (hsPkgs.base) - (hsPkgs.containers) - (hsPkgs.cryptonite) - (hsPkgs.free) - (hsPkgs.goblins) - (hsPkgs.hedgehog) - (hsPkgs.tasty-hunit) - (hsPkgs.lens) - (hsPkgs.mtl) - (hsPkgs.transformers) - (hsPkgs.cardano-crypto-class) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."cryptonite" or (buildDepError "cryptonite")) + (hsPkgs."free" or (buildDepError "free")) + (hsPkgs."goblins" or (buildDepError "goblins")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."tasty-hunit" or (buildDepError "tasty-hunit")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."mtl" or (buildDepError "mtl")) + (hsPkgs."transformers" or (buildDepError "transformers")) + (hsPkgs."cardano-crypto-class" or (buildDepError "cardano-crypto-class")) ]; + buildable = true; }; tests = { "doctests" = { depends = [ - (hsPkgs.base) - (hsPkgs.containers) - (hsPkgs.data-default) - (hsPkgs.free) - (hsPkgs.hedgehog) - (hsPkgs.tasty-hunit) - (hsPkgs.lens) - (hsPkgs.mtl) - (hsPkgs.sequence) - (hsPkgs.transformers) - (hsPkgs.doctest) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."data-default" or (buildDepError "data-default")) + (hsPkgs."free" or (buildDepError "free")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."tasty-hunit" or (buildDepError "tasty-hunit")) + (hsPkgs."lens" or (buildDepError "lens")) + (hsPkgs."mtl" or (buildDepError "mtl")) + (hsPkgs."sequence" or (buildDepError "sequence")) + (hsPkgs."transformers" or (buildDepError "transformers")) + (hsPkgs."doctest" or (buildDepError "doctest")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; build-tools = [ - (hsPkgs.buildPackages.doctest-discover or (pkgs.buildPackages.doctest-discover)) + (hsPkgs.buildPackages.doctest-discover or (pkgs.buildPackages.doctest-discover or (buildToolDepError "doctest-discover"))) ]; + buildable = true; }; "examples" = { depends = [ - (hsPkgs.base) - (hsPkgs.containers) - (hsPkgs.hedgehog) - (hsPkgs.tasty) - (hsPkgs.tasty-hedgehog) - (hsPkgs.tasty-expected-failure) - (hsPkgs.small-steps) + (hsPkgs."base" or (buildDepError "base")) + (hsPkgs."containers" or (buildDepError "containers")) + (hsPkgs."hedgehog" or (buildDepError "hedgehog")) + (hsPkgs."tasty" or (buildDepError "tasty")) + (hsPkgs."tasty-hedgehog" or (buildDepError "tasty-hedgehog")) + (hsPkgs."tasty-expected-failure" or (buildDepError "tasty-expected-failure")) + (hsPkgs."small-steps" or (buildDepError "small-steps")) ]; + buildable = true; }; }; }; diff --git a/nix/iohk-nix-src.json b/nix/iohk-nix-src.json index 863afb4d795..f8f2b668ac1 100644 --- a/nix/iohk-nix-src.json +++ b/nix/iohk-nix-src.json @@ -1,7 +1,7 @@ { "url": "https://github.com/input-output-hk/iohk-nix", - "rev": "11ff3539c21665f9ac20cdf165af632312372b45", - "date": "2019-09-26T16:58:22+00:00", - "sha256": "0bvxjmx341f0ppazcikn9qmdi6nkqgnmw9gj3dkhz9dn6hw838mg", + "rev": "29bbc658a3dcae5c17065b572c442dd7a9379c6e", + "date": "2019-10-22T16:03:42+00:00", + "sha256": "1baqj866ms1q0iwp9lvpipb0jn9d570mapy1jj4npql6zd5015hc", "fetchSubmodules": false } diff --git a/release.nix b/release.nix index 2405b32d21d..87d4243598e 100644 --- a/release.nix +++ b/release.nix @@ -68,16 +68,18 @@ localLib.nix-tools.release-nix { jobs.nix-tools.tests.cs-ledger.ledger-rules-test.x86_64-linux # Windows cross-compilation targets + # + # Also disabled for now due to CI failure (devops is working on fixing this) - jobs.nix-tools.libs.x86_64-pc-mingw32-cs-blockchain.x86_64-linux - jobs.nix-tools.libs.x86_64-pc-mingw32-cs-ledger.x86_64-linux - jobs.nix-tools.libs.x86_64-pc-mingw32-small-steps.x86_64-linux + # jobs.nix-tools.libs.x86_64-pc-mingw32-cs-blockchain.x86_64-linux + # jobs.nix-tools.libs.x86_64-pc-mingw32-cs-ledger.x86_64-linux + # jobs.nix-tools.libs.x86_64-pc-mingw32-small-steps.x86_64-linux ## Doctests don't work in Windows. # jobs.nix-tools.tests.x86_64-pc-mingw32-small-steps.doctests.x86_64-linux - jobs.nix-tools.tests.x86_64-pc-mingw32-small-steps.examples.x86_64-linux - jobs.nix-tools.tests.x86_64-pc-mingw32-cs-blockchain.chain-rules-test.x86_64-linux - jobs.nix-tools.tests.x86_64-pc-mingw32-cs-ledger.ledger-rules-test.x86_64-linux + # jobs.nix-tools.tests.x86_64-pc-mingw32-small-steps.examples.x86_64-linux + # jobs.nix-tools.tests.x86_64-pc-mingw32-cs-blockchain.chain-rules-test.x86_64-linux + # jobs.nix-tools.tests.x86_64-pc-mingw32-cs-ledger.ledger-rules-test.x86_64-linux ]; } (builtins.removeAttrs args ["cardano-ledger-specs"]) diff --git a/shelley/chain-and-ledger/executable-spec/delegation.cabal b/shelley/chain-and-ledger/executable-spec/delegation.cabal index f78cd7358f0..896b4d87d45 100644 --- a/shelley/chain-and-ledger/executable-spec/delegation.cabal +++ b/shelley/chain-and-ledger/executable-spec/delegation.cabal @@ -94,6 +94,7 @@ test-suite delegation-test Generator.Core Generator.LedgerTrace Generator.Delegation + Generator.Update Generator.Utxo PropertyTests STSTests diff --git a/shelley/chain-and-ledger/executable-spec/src/BaseTypes.hs b/shelley/chain-and-ledger/executable-spec/src/BaseTypes.hs index cc4e59bb26f..c48f3d0eb97 100644 --- a/shelley/chain-and-ledger/executable-spec/src/BaseTypes.hs +++ b/shelley/chain-and-ledger/executable-spec/src/BaseTypes.hs @@ -30,6 +30,7 @@ import Numeric.Natural (Natural) import GHC.Generics (Generic) import Cardano.Binary (ToCBOR(..), encodeListLen) import Cardano.Crypto.Hash +import Cardano.Prelude (NoUnexpectedThunks(..)) data E34 @@ -48,7 +49,7 @@ fpEpsilon = (10::FixedPoint)^(17::Integer) / fpPrecision -- | Type to represent a value in the unit interval [0; 1] newtype UnitInterval = UnitInterval Rational - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, NoUnexpectedThunks, ToCBOR) -- | Return a `UnitInterval` type if `r` is in [0; 1]. mkUnitInterval :: Rational -> Maybe UnitInterval @@ -74,7 +75,9 @@ interval1 = UnitInterval 1 data Nonce = Nonce (Hash SHA256 Nonce) | NeutralNonce -- ^ Identity element - deriving (Eq, Ord, Show) + deriving (Eq, Generic, Ord, Show) + +instance NoUnexpectedThunks Nonce instance ToCBOR Nonce where toCBOR NeutralNonce = encodeListLen 1 <> toCBOR (0 :: Word8) @@ -95,7 +98,7 @@ mkNonce = Nonce . coerce . hash @SHA256 -- We do not expose the constructor to `Seed`. Instead, a `Seed` should be -- created using `mkSeed` for a VRF calculation. newtype Seed = Seed (Hash SHA256 Seed) - deriving (Eq, Ord, Show, Generic, ToCBOR) + deriving (Eq, Ord, Show, Generic, NoUnexpectedThunks, ToCBOR) (==>) :: Bool -> Bool -> Bool a ==> b = not a || b diff --git a/shelley/chain-and-ledger/executable-spec/src/BlockChain.hs b/shelley/chain-and-ledger/executable-spec/src/BlockChain.hs index c346d975974..64d7e37373a 100644 --- a/shelley/chain-and-ledger/executable-spec/src/BlockChain.hs +++ b/shelley/chain-and-ledger/executable-spec/src/BlockChain.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeApplications #-} @@ -38,9 +39,11 @@ import Data.Foldable (toList) import qualified Data.Map.Strict as Map import Data.Ratio (denominator, numerator) import Data.Sequence (Seq) +import GHC.Generics (Generic) import Numeric.Natural (Natural) import Cardano.Binary (ToCBOR (toCBOR), encodeListLen) +import Cardano.Prelude (NoUnexpectedThunks(..)) import Cardano.Crypto.Hash (SHA256) import qualified Cardano.Crypto.Hash.Class as Hash import qualified Cardano.Crypto.VRF.Class as VRF @@ -59,7 +62,9 @@ import NonIntegral ((***)) -- |The hash of a Block Header newtype HashHeader hashAlgo dsignAlgo kesAlgo vrfAlgo = HashHeader (Hash hashAlgo (BHeader hashAlgo dsignAlgo kesAlgo vrfAlgo)) - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Generic, Ord, ToCBOR) + +instance NoUnexpectedThunks (HashHeader hashAlgo dsignAlgo kesAlgo vrfAlgo) newtype TxSeq hashAlgo dsignAlgo vrfAlgo = TxSeq (Seq (Tx hashAlgo dsignAlgo vrfAlgo)) @@ -76,7 +81,7 @@ instance -- | Hash of block body newtype HashBBody hashAlgo dsignAlgo kesAlgo vrfAlgo = HashBBody (Hash hashAlgo (TxSeq hashAlgo dsignAlgo vrfAlgo)) - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, ToCBOR) -- |Hash a given block header bhHash @@ -103,7 +108,15 @@ data BHeader hashAlgo dsignAlgo kesAlgo vrfAlgo = BHeader (BHBody hashAlgo dsignAlgo kesAlgo vrfAlgo) (KESig kesAlgo (BHBody hashAlgo dsignAlgo kesAlgo vrfAlgo)) - deriving (Show, Eq) + deriving (Show, Generic, Eq) + +instance + ( HashAlgorithm hashAlgo + , DSIGNAlgorithm dsignAlgo + , KESAlgorithm kesAlgo + , VRFAlgorithm vrfAlgo + ) + => NoUnexpectedThunks (BHeader hashAlgo dsignAlgo kesAlgo vrfAlgo) instance ( HashAlgorithm hashAlgo @@ -119,7 +132,9 @@ instance <> toCBOR kESig data ProtVer = ProtVer Natural Natural Natural - deriving (Show, Eq, Ord) + deriving (Show, Eq, Generic, Ord) + +instance NoUnexpectedThunks ProtVer instance ToCBOR ProtVer where toCBOR (ProtVer x y z) = @@ -153,7 +168,15 @@ data BHBody hashAlgo dsignAlgo kesAlgo vrfAlgo = BHBody , bheaderOCert :: OCert dsignAlgo kesAlgo -- | protocol version , bprotvert :: ProtVer - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance + ( HashAlgorithm hashAlgo + , DSIGNAlgorithm dsignAlgo + , KESAlgorithm kesAlgo + , VRFAlgorithm vrfAlgo + ) + => NoUnexpectedThunks (BHBody hashAlgo dsignAlgo kesAlgo vrfAlgo) instance ( HashAlgorithm hashAlgo diff --git a/shelley/chain-and-ledger/executable-spec/src/Coin.hs b/shelley/chain-and-ledger/executable-spec/src/Coin.hs index a1b7a41d98c..114945da1ea 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Coin.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Coin.hs @@ -8,10 +8,11 @@ module Coin ) where import Cardano.Binary (ToCBOR) +import Cardano.Prelude (NoUnexpectedThunks(..)) -- |The amount of value held by a transaction output. newtype Coin = Coin Integer - deriving (Show, Eq, Ord, Num, Integral, Real, Enum, ToCBOR) + deriving (Show, Eq, Ord, Num, Integral, Real, Enum, NoUnexpectedThunks, ToCBOR) splitCoin :: Coin -> Integer -> (Coin, Coin) splitCoin (Coin n) 0 = (Coin 0, Coin n) diff --git a/shelley/chain-and-ledger/executable-spec/src/Delegation/Certificates.hs b/shelley/chain-and-ledger/executable-spec/src/Delegation/Certificates.hs index db76524e4bb..0affb567fa1 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Delegation/Certificates.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Delegation/Certificates.hs @@ -1,7 +1,8 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Delegation.Certificates ( DCert(..) - , StakeKeys(..) + , StakeCreds(..) , StakePools(..) , PoolDistr(..) , cwitness @@ -13,19 +14,24 @@ module Delegation.Certificates , dderegister , decayKey , decayPool + , isRegKey + , isDeRegKey + , isRegPool + , isInstantaneousRewards ) where import Coin (Coin (..)) -import Keys (Hash, KeyHash, VRFAlgorithm(VerKeyVRF)) +import Keys (Hash, KeyHash, VRFAlgorithm (VerKeyVRF)) import PParams (PParams (..), keyDecayRate, keyDeposit, keyMinRefund, poolDecayRate, poolDeposit, poolMinRefund) import Slot (Duration (..)) -import TxData (Credential (..), DCert (..), StakeCredential, StakeKeys (..), +import TxData (Credential (..), DCert (..), StakeCredential, StakeCreds (..), StakePools (..), delegator, poolPubKey) import BaseTypes (FixedPoint, UnitInterval, fpEpsilon, intervalValue) import NonIntegral (exp') +import Cardano.Prelude (NoUnexpectedThunks (..)) import Data.Map.Strict (Map) import Data.Ratio (approxRational) @@ -39,6 +45,7 @@ cwitness (RegPool pool) = KeyHashObj $ pool ^. poolPubKey cwitness (RetirePool k _) = KeyHashObj k cwitness (Delegate delegation) = delegation ^. delegator cwitness (GenesisDelegate (gk, _)) = GenesisHashObj gk +cwitness (InstantaneousRewards _) = error "no witness in MIR certificate" -- |Retrieve the deposit amount for a certificate dvalue :: DCert hashAlgo dsignAlgo vrfAlgo -> PParams -> Coin @@ -75,6 +82,21 @@ allocating (RegKey _) = True allocating (RegPool _) = True allocating _ = False +-- | Check for `RegKey` constructor +isRegKey :: DCert hashAlgo dsignAlgo vrfAlgo -> Bool +isRegKey (RegKey _) = True +isRegKey _ = False + +-- | Check for `DeRegKey` constructor +isDeRegKey :: DCert hashAlgo dsignAlgo vrfAlgo -> Bool +isDeRegKey (DeRegKey _) = True +isDeRegKey _ = False + +-- | Check for `RegPool` constructor +isRegPool :: DCert hashAlgo dsignAlgo vrfAlgo -> Bool +isRegPool (RegPool _) = True +isRegPool _ = False + decayKey :: PParams -> (Coin, UnitInterval, Rational) decayKey pc = (dval, dmin, lambdad) where dval = fromIntegral $ pc ^. keyDeposit @@ -89,4 +111,8 @@ decayPool pc = (pval, pmin, lambdap) newtype PoolDistr hashAlgo dsignAlgo vrfAlgo = PoolDistr (Map (KeyHash hashAlgo dsignAlgo) (Rational, Hash hashAlgo (VerKeyVRF vrfAlgo))) - deriving (Show, Eq) + deriving (Show, Eq, NoUnexpectedThunks) + +isInstantaneousRewards :: (DCert hashAlgo dsignAlgo vrfAlgo) -> Bool +isInstantaneousRewards (InstantaneousRewards _) = True +isInstantaneousRewards _ = False diff --git a/shelley/chain-and-ledger/executable-spec/src/EpochBoundary.hs b/shelley/chain-and-ledger/executable-spec/src/EpochBoundary.hs index 5234b85a07a..a4ae58085d3 100644 --- a/shelley/chain-and-ledger/executable-spec/src/EpochBoundary.hs +++ b/shelley/chain-and-ledger/executable-spec/src/EpochBoundary.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TupleSections #-} @@ -31,7 +33,7 @@ module EpochBoundary ) where import Coin (Coin (..)) -import Delegation.Certificates (StakeKeys (..), StakePools (..), decayKey, decayPool, +import Delegation.Certificates (StakeCreds (..), StakePools (..), decayKey, decayPool, refund) import Keys (KeyHash) import PParams (PParams (..)) @@ -40,6 +42,7 @@ import TxData (Addr (..), PoolParams, Ptr, RewardAcnt, StakeCredential getRwdCred) import UTxO (UTxO (..)) +import Cardano.Prelude (NoUnexpectedThunks(..)) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe (mapMaybe) @@ -47,7 +50,7 @@ import Data.Ratio ((%)) import qualified Data.Set as Set import Numeric.Natural (Natural) - +import GHC.Generics (Generic) import Lens.Micro.TH (makeLenses) import Ledger.Core (dom, (▷), (◁)) @@ -55,12 +58,12 @@ import Ledger.Core (dom, (▷), (◁)) -- | Blocks made newtype BlocksMade hashAlgo dsignAlgo = BlocksMade (Map (KeyHash hashAlgo dsignAlgo) Natural) - deriving (Show, Eq) + deriving (Show, Eq, NoUnexpectedThunks) -- | Type of stake as map from hash key to coins associated. newtype Stake hashAlgo dsignAlgo = Stake (Map (StakeCredential hashAlgo dsignAlgo) Coin) - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, NoUnexpectedThunks) -- | Add two stake distributions (⊎) @@ -148,11 +151,11 @@ poolRefunds pp retirees cslot = -- | Calculate total possible refunds. obligation :: PParams - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> StakePools hashAlgo dsignAlgo -> Slot -> Coin -obligation pc (StakeKeys stakeKeys) (StakePools stakePools) cslot = +obligation pc (StakeCreds stakeKeys) (StakePools stakePools) cslot = sum (map (\s -> refund dval dmin lambdad (cslot -* s)) $ Map.elems stakeKeys) + sum (map (\s -> refund pval pmin lambdap (cslot -* s)) $ Map.elems stakePools) where @@ -204,7 +207,9 @@ data SnapShots hashAlgo dsignAlgo vrfAlgo , _poolsSS :: Map (KeyHash hashAlgo dsignAlgo) (PoolParams hashAlgo dsignAlgo vrfAlgo) , _feeSS :: Coin - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (SnapShots hashAlgo dsignAlgo vrfAlgo) makeLenses ''SnapShots diff --git a/shelley/chain-and-ledger/executable-spec/src/Keys.hs b/shelley/chain-and-ledger/executable-spec/src/Keys.hs index cc04b8eac8d..1eb85fc15d1 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Keys.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Keys.hs @@ -1,11 +1,10 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} @@ -38,7 +37,7 @@ module Keys , verify , GKeys(..) - , Dms(..) + , GenDelegs(..) , KESAlgorithm , KESignable @@ -61,15 +60,17 @@ import Crypto.Random (drgNewSeed, seedFromInteger, withDRG) import Data.Maybe (fromJust) import Data.Ratio ((%)) import Data.Typeable (Typeable) +import GHC.Generics (Generic) import Numeric.Natural (Natural) import Data.Map.Strict (Map) import Data.Set (Set) import BaseTypes (Nonce, UnitInterval, mkNonce, truncateUnitInterval) -import Cardano.Binary (ToCBOR (toCBOR)) -import Cardano.Crypto.DSIGN (DSIGNAlgorithm (SignKeyDSIGN, Signable, VerKeyDSIGN, encodeSigDSIGN, encodeVerKeyDSIGN), +import Cardano.Binary (ToCBOR (toCBOR), FromCBOR(..)) +import Cardano.Crypto.DSIGN (DSIGNAlgorithm (SignKeyDSIGN, Signable, VerKeyDSIGN, encodeVerKeyDSIGN), SignedDSIGN (SignedDSIGN), signedDSIGN, verifySignedDSIGN) +import qualified Cardano.Crypto.DSIGN as DSIGN import Cardano.Crypto.Hash (Hash, HashAlgorithm, hash, hashWithSerialiser) import Cardano.Crypto.KES (KESAlgorithm (SignKeyKES, VerKeyKES, encodeSigKES, encodeVerKeyKES), @@ -77,6 +78,7 @@ import Cardano.Crypto.KES import qualified Cardano.Crypto.KES as KES import Cardano.Crypto.VRF (VRFAlgorithm (VerKeyVRF)) import qualified Cardano.Crypto.VRF as VRF +import Cardano.Prelude (NoUnexpectedThunks(..)) -- | Discriminate between keys based on their usage in the system. data KeyDiscriminator @@ -86,6 +88,8 @@ data KeyDiscriminator newtype SKey dsignAlgo = SKey (SignKeyDSIGN dsignAlgo) +deriving instance DSIGNAlgorithm dsignAlgo => NoUnexpectedThunks (SKey dsignAlgo) + deriving instance DSIGNAlgorithm dsignAlgo => Show (SKey dsignAlgo) deriving instance Num (SignKeyDSIGN dsignAlgo) => Num (SKey dsignAlgo) @@ -95,7 +99,10 @@ newtype DiscVKey (kd :: KeyDiscriminator) dsignAlgo = DiscVKey (VerKeyDSIGN dsig deriving instance DSIGNAlgorithm dsignAlgo => Show (DiscVKey kd dsignAlgo) deriving instance DSIGNAlgorithm dsignAlgo => Eq (DiscVKey kd dsignAlgo) deriving instance Num (VerKeyDSIGN dsignAlgo) => Num (DiscVKey kd dsignAlgo) +deriving instance DSIGNAlgorithm dsignAlgo => NoUnexpectedThunks (DiscVKey kd dsignAlgo) +instance (DSIGNAlgorithm dsignAlgo, Typeable kd) => FromCBOR (DiscVKey kd dsignAlgo) where + fromCBOR = DiscVKey <$> DSIGN.decodeVerKeyDSIGN instance (DSIGNAlgorithm dsignAlgo, Typeable kd) => ToCBOR (DiscVKey kd dsignAlgo) where toCBOR (DiscVKey vk) = encodeVerKeyDSIGN vk @@ -110,15 +117,21 @@ data KeyPair (kd :: KeyDiscriminator) dsignAlgo = KeyPair { vKey :: DiscVKey kd dsignAlgo , sKey :: SKey dsignAlgo - } deriving (Show) + } deriving (Generic, Show) + +instance DSIGNAlgorithm dsignAlgo => NoUnexpectedThunks (KeyPair kd dsignAlgo) newtype Sig dsignAlgo a = Sig (SignedDSIGN dsignAlgo a) deriving instance (DSIGNAlgorithm dsignAlgo) => Show (Sig dsignAlgo a) deriving instance (DSIGNAlgorithm dsignAlgo) => Eq (Sig dsignAlgo a) +deriving instance DSIGNAlgorithm dsignAlgo => NoUnexpectedThunks (Sig dsignAlgo a) +instance (DSIGNAlgorithm dsignAlgo, Typeable a) => FromCBOR (Sig dsignAlgo a) where + fromCBOR = Sig <$> DSIGN.decodeSignedDSIGN instance (DSIGNAlgorithm dsignAlgo, Typeable a) => ToCBOR (Sig dsignAlgo a) where - toCBOR (Sig (SignedDSIGN sigDSIGN)) = encodeSigDSIGN sigDSIGN + toCBOR (Sig s) = DSIGN.encodeSignedDSIGN s + -- |Produce a digital signature sign :: (DSIGNAlgorithm dsignAlgo, Signable dsignAlgo a) @@ -149,9 +162,12 @@ newtype VKeyES kesAlgo = VKeyES (VerKeyKES kesAlgo) deriving instance (KESAlgorithm kesAlgo) => Show (VKeyES kesAlgo) deriving instance (KESAlgorithm kesAlgo) => Eq (VKeyES kesAlgo) +deriving instance (KESAlgorithm kesAlgo) => NoUnexpectedThunks (VKeyES kesAlgo) instance KESAlgorithm kesAlgo => ToCBOR (VKeyES kesAlgo) where toCBOR (VKeyES vKeyES) = encodeVerKeyKES vKeyES +instance KESAlgorithm kesAlgo => FromCBOR (VKeyES kesAlgo) where + fromCBOR = VKeyES <$> KES.decodeVerKeyKES type KESignable kesAlgo a = KES.Signable kesAlgo a @@ -159,6 +175,7 @@ newtype KESig kesAlgo a = KESig (SignedKES kesAlgo a) deriving instance (KESAlgorithm kesAlgo) => Show (KESig kesAlgo a) deriving instance (KESAlgorithm kesAlgo) => Eq (KESig kesAlgo a) +deriving instance (KESAlgorithm kesAlgo) => NoUnexpectedThunks (KESig kesAlgo a) instance (KESAlgorithm kesAlgo, Typeable a) => ToCBOR (KESig kesAlgo a) where toCBOR (KESig (SignedKES sigKES)) = encodeSigKES sigKES @@ -191,12 +208,12 @@ verifyKES (VKeyES vKeyES) vd (KESig sigKES) n = either (const False) (const True) $ verifySignedKES vKeyES n vd sigKES -newtype Dms hashAlgo dsignAlgo = - Dms (Map (GenKeyHash hashAlgo dsignAlgo) (KeyHash hashAlgo dsignAlgo)) - deriving (Show, Eq) +newtype GenDelegs hashAlgo dsignAlgo = + GenDelegs (Map (GenKeyHash hashAlgo dsignAlgo) (KeyHash hashAlgo dsignAlgo)) + deriving (Show, Eq, NoUnexpectedThunks) newtype GKeys dsignAlgo = GKeys (Set (VKeyGenesis dsignAlgo)) - deriving (Show, Eq) + deriving (Show, Eq, NoUnexpectedThunks) -------------------------------------------------------------------------------- -- Key Hashes @@ -205,7 +222,7 @@ newtype GKeys dsignAlgo = GKeys (Set (VKeyGenesis dsignAlgo)) -- | Discriminated hash of public Key newtype DiscKeyHash (discriminator :: KeyDiscriminator) hashAlgo dsignAlgo = DiscKeyHash (Hash hashAlgo (VerKeyDSIGN dsignAlgo)) - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, ToCBOR) type KeyHash hashAlgo dsignAlgo = DiscKeyHash 'Regular hashAlgo dsignAlgo pattern KeyHash @@ -217,7 +234,7 @@ type GenKeyHash hashAlgo dsignAlgo = DiscKeyHash 'Genesis hashAlgo dsignAlgo -- | Discriminated hash of public Key newtype AnyKeyHash hashAlgo dsignAlgo = AnyKeyHash (Hash hashAlgo (VerKeyDSIGN dsignAlgo)) - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, ToCBOR) undiscriminateKeyHash :: DiscKeyHash kd hashAlgo dsignAlgo diff --git a/shelley/chain-and-ledger/executable-spec/src/LedgerState.hs b/shelley/chain-and-ledger/executable-spec/src/LedgerState.hs index 4c5790ab158..0978ba9b5af 100644 --- a/shelley/chain-and-ledger/executable-spec/src/LedgerState.hs +++ b/shelley/chain-and-ledger/executable-spec/src/LedgerState.hs @@ -1,6 +1,8 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} @@ -33,8 +35,9 @@ module LedgerState , dstate , pstate , ptrs - , fdms - , dms + , fGenDelegs + , genDelegs + , irwd , PState(..) , cCounters , LedgerValidation(..) @@ -55,9 +58,6 @@ module LedgerState , delegatedStake , retirePools , emptyDelegation - , applyDCert - , applyDCertDState - , applyDCertPState , applyUTxOUpdate -- * Genesis State , genesisId @@ -89,7 +89,7 @@ module LedgerState , ups -- DelegationState , rewards - , stKeys + , stkCreds , delegations , stPools , pParams @@ -118,8 +118,10 @@ module LedgerState , updateNES ) where +import Cardano.Prelude (NoUnexpectedThunks (..)) import Control.Monad (foldM) import Data.Foldable (toList) +import Delegation.Certificates (isInstantaneousRewards) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe, mapMaybe) @@ -127,16 +129,18 @@ import Data.Ratio ((%)) import qualified Data.Sequence as Seq (Seq (..)) import Data.Set (Set) import qualified Data.Set as Set +import GHC.Generics (Generic) import Numeric.Natural (Natural) import Lens.Micro (to, (%~), (&), (.~), (^.)) import Lens.Micro.TH (makeLenses) +import Address (mkRwdAcnt) import Coin (Coin (..)) import EpochBoundary (BlocksMade (..), SnapShots (..), Stake (..), aggregateOuts, baseStake, emptySnapShots, maxPool, poolRefunds, poolStake, ptrStake, rewardStake) -import Keys (AnyKeyHash, DSIGNAlgorithm, Dms (..), GenKeyHash, HashAlgorithm, +import Keys (AnyKeyHash, DSIGNAlgorithm, GenDelegs (..), GenKeyHash, HashAlgorithm, KeyDiscriminator (..), KeyHash, KeyPair, Signable, VRFAlgorithm, hash, undiscriminateKeyHash) import PParams (PParams (..), activeSlotCoeff, d, emptyPParams, keyDecayRate, keyDeposit, @@ -152,7 +156,7 @@ import Updates (AVUpdate (..), PPUpdate (..), Update (..), UpdateState emptyUpdateState) import UTxO (UTxO (..), balance, deposits, txinLookup, txins, txouts, txup, verifyWitVKey) -import Delegation.Certificates (DCert (..), PoolDistr (..), StakeKeys (..), +import Delegation.Certificates (DCert (..), PoolDistr (..), StakeCreds (..), StakePools (..), cwitness, decayKey, refund) import Delegation.PoolParams (poolSpec) @@ -167,7 +171,9 @@ type KeyPairs dsignAlgo = [(KeyPair 'Regular dsignAlgo, KeyPair 'Regular dsignAl -- validation errors that occurred from a valid 's' to reach 't'. data LedgerValidation hashAlgo dsignAlgo vrfAlgo = LedgerValidation [ValidationError] (LedgerState hashAlgo dsignAlgo vrfAlgo) - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (LedgerValidation hashAlgo dsignAlgo vrfAlgo) -- |Validation errors represent the failures of a transaction to be valid -- for a given ledger state. @@ -198,7 +204,9 @@ data ValidationError = | StakeDelegationImpossible -- | Stake pool not registered for key, cannot be retired. | StakePoolNotRegisteredOnKey - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks ValidationError -- |The validity of a transaction, where an invalid transaction -- is represented by list of errors. @@ -219,7 +227,7 @@ type RewardAccounts hashAlgo dsignAlgo -- | StakeShare type newtype StakeShare = StakeShare Rational - deriving (Show, Ord, Eq) + deriving (Show, Ord, Eq, NoUnexpectedThunks) -- | Construct an optional probability value mkStakeShare :: Rational -> Maybe StakeShare @@ -230,7 +238,7 @@ mkStakeShare p = data DState hashAlgo dsignAlgo = DState { -- |The active stake keys. - _stKeys :: StakeKeys hashAlgo dsignAlgo + _stkCreds :: StakeCreds hashAlgo dsignAlgo -- |The active accounts. , _rewards :: RewardAccounts hashAlgo dsignAlgo -- |The current delegations. @@ -238,10 +246,14 @@ data DState hashAlgo dsignAlgo = DState -- |The pointed to hash keys. , _ptrs :: Map Ptr (StakeCredential hashAlgo dsignAlgo) -- | future genesis key delegations - , _fdms :: Map (Slot, GenKeyHash hashAlgo dsignAlgo) (KeyHash hashAlgo dsignAlgo) + , _fGenDelegs :: Map (Slot, GenKeyHash hashAlgo dsignAlgo) (KeyHash hashAlgo dsignAlgo) -- |Genesis key delegations - , _dms :: Dms hashAlgo dsignAlgo - } deriving (Show, Eq) + , _genDelegs :: GenDelegs hashAlgo dsignAlgo + -- | Instantaneous Rewards + , _irwd :: Map (Credential hashAlgo dsignAlgo) Coin + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (DState hashAlgo dsignAlgo) data PState hashAlgo dsignAlgo vrfAlgo = PState { -- |The active stake pools. @@ -252,7 +264,9 @@ data PState hashAlgo dsignAlgo vrfAlgo = PState , _retiring :: Map (KeyHash hashAlgo dsignAlgo) Epoch -- | Operational Certificate Counters. , _cCounters :: Map (KeyHash hashAlgo dsignAlgo) Natural - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (PState hashAlgo dsignAlgo vrfAlgo) -- |The state associated with the current stake delegation. data DPState hashAlgo dsignAlgo vrfAlgo = @@ -260,22 +274,30 @@ data DPState hashAlgo dsignAlgo vrfAlgo = { _dstate :: DState hashAlgo dsignAlgo , _pstate :: PState hashAlgo dsignAlgo vrfAlgo - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (DPState hashAlgo dsignAlgo vrfAlgo) data RewardUpdate hashAlgo dsignAlgo = RewardUpdate - { deltaT :: Coin - , deltaR :: Coin - , rs :: Map (RewardAcnt hashAlgo dsignAlgo) Coin - , deltaF :: Coin - } deriving (Show, Eq) + { deltaT :: Coin + , deltaR :: Coin + , rs :: Map (RewardAcnt hashAlgo dsignAlgo) Coin + , deltaF :: Coin + , deltaDeposits :: Coin + , updateIRwd :: Map (Credential hashAlgo dsignAlgo) Coin + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (RewardUpdate hashAlgo dsignAlgo) emptyRewardUpdate :: RewardUpdate hashAlgo dsignAlgo -emptyRewardUpdate = RewardUpdate (Coin 0) (Coin 0) Map.empty (Coin 0) +emptyRewardUpdate = RewardUpdate (Coin 0) (Coin 0) Map.empty (Coin 0) (Coin 0) Map.empty data AccountState = AccountState { _treasury :: Coin , _reserves :: Coin - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks AccountState data EpochState hashAlgo dsignAlgo vrfAlgo = EpochState @@ -284,7 +306,9 @@ data EpochState hashAlgo dsignAlgo vrfAlgo , esLState :: LedgerState hashAlgo dsignAlgo vrfAlgo , esPp :: PParams } - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (EpochState hashAlgo dsignAlgo vrfAlgo) emptyUTxOState :: UTxOState hashAlgo dsignAlgo vrfAlgo emptyUTxOState = UTxOState (UTxO Map.empty) (Coin 0) (Coin 0) emptyUpdateState @@ -309,7 +333,7 @@ emptyDelegation = emptyDState :: DState hashAlgo dsignAlgo emptyDState = - DState (StakeKeys Map.empty) Map.empty Map.empty Map.empty Map.empty (Dms Map.empty) + DState (StakeCreds Map.empty) Map.empty Map.empty Map.empty Map.empty (GenDelegs Map.empty) Map.empty emptyPState :: PState hashAlgo dsignAlgo vrfAlgo emptyPState = @@ -329,7 +353,9 @@ data UTxOState hashAlgo dsignAlgo vrfAlgo = , _deposited :: Coin , _fees :: Coin , _ups :: UpdateState hashAlgo dsignAlgo - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (UTxOState hashAlgo dsignAlgo vrfAlgo) -- | New Epoch state and environment data NewEpochState hashAlgo dsignAlgo vrfAlgo = @@ -342,22 +368,26 @@ data NewEpochState hashAlgo dsignAlgo vrfAlgo = , nesRu :: Maybe (RewardUpdate hashAlgo dsignAlgo) , nesPd :: PoolDistr hashAlgo dsignAlgo vrfAlgo , nesOsched :: Map Slot (Maybe (GenKeyHash hashAlgo dsignAlgo)) - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (NewEpochState hashAlgo dsignAlgo vrfAlgo) getGKeys :: NewEpochState hashAlgo dsignAlgo vrfAlgo -> Set (GenKeyHash hashAlgo dsignAlgo) -getGKeys nes = Map.keysSet dms +getGKeys nes = Map.keysSet genDelegs where NewEpochState _ _ _ _ es _ _ _ = nes EpochState _ _ ls _ = es - LedgerState _ (DPState (DState _ _ _ _ _ (Dms dms)) _) _ = ls + LedgerState _ (DPState (DState _ _ _ _ _ (GenDelegs genDelegs) _) _) _ = ls data NewEpochEnv hashAlgo dsignAlgo = NewEpochEnv { neeEta1 :: Nonce , neeS :: Slot , neeGkeys :: Set (GenKeyHash hashAlgo dsignAlgo) - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (NewEpochEnv hashAlgo dsignAlgo) -- |The state associated with a 'Ledger'. data LedgerState hashAlgo dsignAlgo vrfAlgo = @@ -368,7 +398,9 @@ data LedgerState hashAlgo dsignAlgo vrfAlgo = , _delegationState :: !(DPState hashAlgo dsignAlgo vrfAlgo) -- |The current transaction index in the current slot. , _txSlotIx :: Ix - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (LedgerState hashAlgo dsignAlgo vrfAlgo) makeLenses ''DPState makeLenses ''DState @@ -470,7 +502,7 @@ produced pp stakePools tx = -- |Compute the key deregistration refunds in a transaction keyRefunds :: PParams - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> TxBody hashAlgo dsignAlgo vrfAlgo -> Coin keyRefunds pp stk tx = @@ -482,13 +514,13 @@ keyRefund :: Coin -> UnitInterval -> Rational - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> Slot -> DCert hashAlgo dsignAlgo vrfAlgo -> Coin -keyRefund dval dmin lambda (StakeKeys stkeys) slot c = +keyRefund dval dmin lambda (StakeCreds stkcreds) slot c = case c of - DeRegKey key -> case Map.lookup key stkeys of + DeRegKey key -> case Map.lookup key stkcreds of Nothing -> Coin 0 Just s -> refund dval dmin lambda $ slot -* s _ -> Coin 0 @@ -496,16 +528,16 @@ keyRefund dval dmin lambda (StakeKeys stkeys) slot c = -- | Functions to calculate decayed deposits decayedKey :: PParams - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> Slot -> DCert hashAlgo dsignAlgo vrfAlgo -> Coin -decayedKey pp stk@(StakeKeys stkeys) cslot cert = +decayedKey pp stk@(StakeCreds stkcreds) cslot cert = case cert of DeRegKey key -> - if Map.notMember key stkeys + if Map.notMember key stkcreds then 0 - else let created' = stkeys Map.! key in + else let created' = stkcreds Map.! key in let start = max (firstSlot $ epochFromSlot cslot) created' in let dval = pp ^. keyDeposit in let dmin = pp ^. keyMinRefund in @@ -518,7 +550,7 @@ decayedKey pp stk@(StakeKeys stkeys) cslot cert = -- | Decayed deposit portions decayedTx :: PParams - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> TxBody hashAlgo dsignAlgo vrfAlgo -> Coin decayedTx pp stk tx = @@ -528,7 +560,7 @@ decayedTx pp stk tx = consumed :: PParams -> UTxO hashAlgo dsignAlgo vrfAlgo - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> TxBody hashAlgo dsignAlgo vrfAlgo -> Coin consumed pp u stakeKeys tx = @@ -542,7 +574,7 @@ consumed pp u stakeKeys tx = preserveBalance :: (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo, VRFAlgorithm vrfAlgo) => StakePools hashAlgo dsignAlgo - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> PParams -> TxBody hashAlgo dsignAlgo vrfAlgo -> UTxOState hashAlgo dsignAlgo vrfAlgo @@ -572,9 +604,9 @@ correctWithdrawals accs withdrawals = witsVKeyNeeded :: UTxO hashAlgo dsignAlgo vrfAlgo -> Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> Set (AnyKeyHash hashAlgo dsignAlgo) -witsVKeyNeeded utxo' tx@(Tx txbody _ _) _dms = +witsVKeyNeeded utxo' tx@(Tx txbody _ _) _genDelegs = inputAuthors `Set.union` wdrlAuthors `Set.union` certAuthors `Set.union` @@ -591,9 +623,10 @@ witsVKeyNeeded utxo' tx@(Tx txbody _ _) _dms = Set.fromList $ extractKeyHash $ map getRwdCred (Map.keys (txbody ^. wdrls)) owners = foldl Set.union Set.empty [pool ^. poolOwners . to (Set.map undiscriminateKeyHash) | RegPool pool <- toList $ txbody ^. certs] - certAuthors = Set.fromList $ extractKeyHash (fmap getCertHK (toList $ txbody ^. certs)) + certAuthors = Set.fromList $ extractKeyHash (fmap getCertHK certificates) getCertHK = cwitness - updateKeys = undiscriminateKeyHash `Set.map` propWits (txup tx) _dms + certificates = filter (not . isInstantaneousRewards) (toList $ txbody ^. certs) + updateKeys = undiscriminateKeyHash `Set.map` propWits (txup tx) _genDelegs -- |Given a ledger state, determine if the UTxO witnesses in a given -- transaction are correct. @@ -616,7 +649,7 @@ verifiedWits (Tx tx wits _) = enoughWits :: (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> UTxOState hashAlgo dsignAlgo vrfAlgo -> Validity enoughWits tx@(Tx _ wits _) d' u = @@ -630,7 +663,7 @@ validRuleUTXO :: (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo, VRFAlgorithm vrfAlgo) => RewardAccounts hashAlgo dsignAlgo -> StakePools hashAlgo dsignAlgo - -> StakeKeys hashAlgo dsignAlgo + -> StakeCreds hashAlgo dsignAlgo -> PParams -> Slot -> TxBody hashAlgo dsignAlgo vrfAlgo @@ -650,7 +683,7 @@ validRuleUTXOW , Signable dsignAlgo (TxBody hashAlgo dsignAlgo vrfAlgo) ) => Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> LedgerState hashAlgo dsignAlgo vrfAlgo -> Validity validRuleUTXOW tx d' l = verifiedWits tx @@ -660,11 +693,11 @@ validRuleUTXOW tx d' l = verifiedWits tx -- proposals. propWits :: Update hashAlgo dsignAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> Set (KeyHash hashAlgo dsignAlgo) -propWits (Update (PPUpdate pup) (AVUpdate aup')) (Dms _dms) = +propWits (Update (PPUpdate pup) (AVUpdate aup')) (GenDelegs _genDelegs) = Set.fromList $ Map.elems updateKeys - where updateKeys = (Map.keysSet pup `Set.union` Map.keysSet aup') ◁ _dms + where updateKeys = (Map.keysSet pup `Set.union` Map.keysSet aup') ◁ _genDelegs validTx :: ( HashAlgorithm hashAlgo @@ -673,7 +706,7 @@ validTx , Signable dsignAlgo (TxBody hashAlgo dsignAlgo vrfAlgo) ) => Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> Slot -> PParams -> LedgerState hashAlgo dsignAlgo vrfAlgo @@ -681,7 +714,7 @@ validTx validTx tx d' slot pp l = validRuleUTXO (l ^. delegationState . dstate . rewards) (l ^. delegationState . pstate . stPools) - (l ^. delegationState . dstate . stKeys) + (l ^. delegationState . dstate . stkCreds) pp slot (tx ^. body) @@ -702,7 +735,7 @@ validKeyRegistration cert ds = case cert of RegKey key -> if not $ Map.member key stakeKeys then Valid else Invalid [StakeKeyAlreadyRegistered] - where (StakeKeys stakeKeys) = ds ^. stKeys + where (StakeCreds stakeKeys) = ds ^. stkCreds _ -> Valid validKeyDeregistration @@ -713,7 +746,7 @@ validKeyDeregistration cert ds = case cert of DeRegKey key -> if Map.member key stakeKeys then Valid else Invalid [StakeKeyNotRegistered] - where (StakeKeys stakeKeys) = ds ^. stKeys + where (StakeCreds stakeKeys) = ds ^. stkCreds _ -> Valid validStakeDelegation @@ -725,7 +758,7 @@ validStakeDelegation cert ds = Delegate (Delegation source _) -> if Map.member source stakeKeys then Valid else Invalid [StakeDelegationImpossible] - where (StakeKeys stakeKeys) = ds ^. stKeys + where (StakeCreds stakeKeys) = ds ^. stkCreds _ -> Valid -- there is currently no requirement that could make this invalid @@ -770,7 +803,7 @@ asStateTransition -> PParams -> LedgerState hashAlgo dsignAlgo vrfAlgo -> Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> Either [ValidationError] (LedgerState hashAlgo dsignAlgo vrfAlgo) asStateTransition slot pp ls tx d' = case validTx tx d' slot pp ls of @@ -806,7 +839,7 @@ asStateTransition' -> PParams -> LedgerValidation hashAlgo dsignAlgo vrfAlgo -> Tx hashAlgo dsignAlgo vrfAlgo - -> Dms hashAlgo dsignAlgo + -> GenDelegs hashAlgo dsignAlgo -> LedgerValidation hashAlgo dsignAlgo vrfAlgo asStateTransition' slot pp (LedgerValidation valErrors ls) tx d' = let ls' = applyTxBody ls pp (tx ^. body) in @@ -845,7 +878,7 @@ depositPoolChange ls pp tx = (currentPool + txDeposits) - txRefunds currentPool = ls ^. utxoState . deposited txDeposits = deposits pp (ls ^. delegationState . pstate . stPools) (toList $ tx ^. certs) - txRefunds = keyRefunds pp (ls ^. delegationState . dstate . stKeys) tx + txRefunds = keyRefunds pp (ls ^. delegationState . dstate . stkCreds) tx -- |Apply a transaction body as a state transition function on the ledger state. applyTxBody @@ -898,6 +931,8 @@ applyDCert ptr dcert@(RetirePool _ _) ds = applyDCert _ (GenesisDelegate _) ds = ds -- TODO: check this +applyDCert _ (InstantaneousRewards _) _ = undefined + -- TODO do we also have to check hashKey target? applyDCert ptr dcert@(Delegate _) ds = ds & dstate %~ applyDCertDState ptr dcert @@ -908,19 +943,19 @@ applyDCertDState -> DState hashAlgo dsignAlgo -> DState hashAlgo dsignAlgo applyDCertDState (Ptr slot txIx clx) (DeRegKey key) ds = - ds & stKeys .~ (StakeKeys $ Map.delete hksk stkeys') + ds & stkCreds .~ (StakeCreds $ Map.delete hksk stkcreds') & rewards %~ Map.delete (RewardAcnt hksk) & delegations %~ Map.delete hksk & ptrs %~ Map.delete (Ptr slot txIx clx) where hksk = key - (StakeKeys stkeys') = ds ^. stKeys + (StakeCreds stkcreds') = ds ^. stkCreds applyDCertDState (Ptr slot txIx clx) (RegKey key) ds = - ds & stKeys .~ (StakeKeys $ Map.insert hksk slot stkeys') + ds & stkCreds .~ (StakeCreds $ Map.insert hksk slot stkcreds') & rewards %~ Map.insert (RewardAcnt hksk) (Coin 0) & ptrs %~ Map.insert (Ptr slot txIx clx) hksk where hksk = key - (StakeKeys stkeys') = ds ^. stKeys + (StakeCreds stkcreds') = ds ^. stkCreds applyDCertDState _ (Delegate (Delegation source target)) ds = ds & delegations %~ Map.insert source target @@ -1096,23 +1131,24 @@ stakeDistr stakeDistr u ds ps = ( Stake $ dom activeDelegs ◁ aggregatePlus stakeRelation , delegs) where - DState (StakeKeys stkeys) rewards' delegs ptrs' _ _ = ds - PState (StakePools stpools) _ _ _ = ps + DState (StakeCreds stkcreds) rewards' delegs ptrs' _ _ _ = ds + PState (StakePools stpools) _ _ _ = ps outs = aggregateOuts u stakeRelation :: [(StakeCredential hashAlgo dsignAlgo, Coin)] stakeRelation = baseStake outs ∪ ptrStake outs ptrs' ∪ rewardStake rewards' - activeDelegs = dom stkeys ◁ delegs ▷ dom stpools + activeDelegs = dom stkcreds ◁ delegs ▷ dom stpools aggregatePlus = Map.fromListWith (+) -- | Apply a reward update applyRUpd :: RewardUpdate hashAlgo dsignAlgo + -> Epoch -> EpochState hashAlgo dsignAlgo vrfAlgo -> EpochState hashAlgo dsignAlgo vrfAlgo -applyRUpd ru (EpochState as ss ls pp) = EpochState as' ss ls' pp +applyRUpd ru e (EpochState as ss ls pp) = EpochState as' ss ls' pp where utxoState_ = _utxoState ls delegState = _delegationState ls dState = _dstate delegState @@ -1121,9 +1157,19 @@ applyRUpd ru (EpochState as ss ls pp) = EpochState as' ss ls' pp , _reserves = _reserves as + deltaR ru } ls' = ls { _utxoState = - utxoState_ {_fees = _fees utxoState_ + deltaF ru } + utxoState_ { _fees = _fees utxoState_ + deltaF ru + , _deposited = _deposited utxoState_ + deltaDeposits ru} , _delegationState = - delegState {_dstate = dState {_rewards = _rewards dState ∪+ rs ru}}} + delegState + {_dstate = dState + { _rewards = (_rewards dState ∪+ rs ru) ∪+ updateRwd + , _stkCreds = StakeCreds $ updateDelegs ∪ stkcreds + , _irwd = Map.empty + }}} + StakeCreds stkcreds = _stkCreds dState + rewMir = updateIRwd ru + updateDelegs = Map.fromList [(cred, firstSlot e) | cred <- Map.keys rewMir] + updateRwd = Map.mapKeys mkRwdAcnt rewMir -- | Create a reward update createRUpd @@ -1131,22 +1177,45 @@ createRUpd -> EpochState hashAlgo dsignAlgo vrfAlgo -> RewardUpdate hashAlgo dsignAlgo createRUpd b@(BlocksMade b') (EpochState acnt ss ls pp) = - RewardUpdate (Coin $ deltaT1 + deltaT2) (-deltaR') rs' (-(_feeSS ss)) + RewardUpdate (Coin $ deltaT1 + deltaT2) (-deltaR') rs' (-(_feeSS ss)) deltaD newIrwd where Coin reserves' = _reserves acnt - deltaR' = - floor $ min 1 eta * intervalValue (_rho pp) * fromIntegral reserves' - Coin totalPot = _feeSS ss + deltaR' - deltaT1 = floor $ intervalValue (_tau pp) * fromIntegral totalPot - r@(Coin r') = Coin $ totalPot - deltaT1 - rewards' = _rewards $ _dstate $ _delegationState ls + + ds = _dstate $ _delegationState ls + rewards' = _rewards ds (stake', delegs') = _pstakeGo ss poolsSS' = _poolsSS ss + StakeCreds stkcreds = _stkCreds ds + + -- instantaneous rewards + unregistered = Map.filterWithKey (\cred _ -> cred `Map.member` stkcreds) (_irwd ds) + registered = Map.difference (_irwd ds) unregistered + rewardsInsufficient = Map.filter (<= _keyDeposit pp) unregistered + newlyRegister = Map.difference unregistered rewardsInsufficient + + Coin rewardsMIR = (Map.foldl (+) (Coin 0) registered) + + (Map.foldl (+) (Coin 0) newlyRegister) + + newlyRegister' = Map.map (flip (-) $ _keyDeposit pp) newlyRegister + reserves'' = reserves' - rewardsMIR + deltaD = Coin $ fromIntegral $ Map.size newlyRegister' + newIrwd = Map.union registered newlyRegister' + + -- reserves and rewards change + deltaRl = + (floor $ min 1 eta * intervalValue (_rho pp) * fromIntegral reserves'') + deltaR' = deltaRl + Coin rewardsMIR + eta = fromIntegral blocksMade / expectedBlocks + + Coin rewardPot = _feeSS ss + deltaRl + deltaT1 = floor $ intervalValue (_tau pp) * fromIntegral rewardPot + r@(Coin r') = Coin $ rewardPot - deltaT1 + deltaT2 = r' - c' rs' = reward pp b r (Map.keysSet rewards') poolsSS' stake' delegs' Coin c' = Map.foldr (+) (Coin 0) rs' + blocksMade = fromIntegral $ Map.foldr (+) 0 b' :: Integer expectedBlocks = intervalValue (_activeSlotCoeff pp) * fromIntegral slotsPerEpoch - eta = fromIntegral blocksMade / expectedBlocks -- | Overlay schedule -- This is just a very simple round-robin, evenly spaced schedule. diff --git a/shelley/chain-and-ledger/executable-spec/src/OCert.hs b/shelley/chain-and-ledger/executable-spec/src/OCert.hs index e62e6dfa7ed..6ea7f6a7bf6 100644 --- a/shelley/chain-and-ledger/executable-spec/src/OCert.hs +++ b/shelley/chain-and-ledger/executable-spec/src/OCert.hs @@ -1,4 +1,6 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE OverloadedStrings #-} module OCert ( OCert(..) @@ -7,7 +9,10 @@ module OCert , kesPeriod) where -import Cardano.Binary (ToCBOR, encodeListLen, toCBOR) +import Cardano.Binary (FromCBOR(..), ToCBOR, encodeListLen + , enforceSize, toCBOR) +import Cardano.Prelude (NoUnexpectedThunks(..)) +import GHC.Generics (Generic) import Keys (DSIGNAlgorithm, KESAlgorithm, Sig, VKey, VKeyES) import Slot (Slot (..)) @@ -15,7 +20,7 @@ import Slot (Slot (..)) import Numeric.Natural (Natural) newtype KESPeriod = KESPeriod Natural - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, FromCBOR, ToCBOR) data OCert dsignAlgo kesAlgo = OCert { -- | The operational hot key @@ -28,7 +33,12 @@ data OCert dsignAlgo kesAlgo = OCert , ocertKESPeriod :: KESPeriod -- | Signature of block operational certificate content , ocertSigma :: Sig dsignAlgo (VKeyES kesAlgo, Natural, KESPeriod) - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance + ( DSIGNAlgorithm dsignAlgo + , KESAlgorithm kesAlgo + ) => NoUnexpectedThunks (OCert dsignAlgo kesAlgo) instance (DSIGNAlgorithm dsignAlgo, KESAlgorithm kesAlgo) @@ -42,6 +52,18 @@ instance <> toCBOR (ocertKESPeriod ocert) <> toCBOR (ocertSigma ocert) +instance + (DSIGNAlgorithm dsignAlgo, KESAlgorithm kesAlgo) + => FromCBOR (OCert dsignAlgo kesAlgo) + where + fromCBOR = enforceSize "OCert should have 5 fields" 5 >> + OCert + <$> fromCBOR + <*> fromCBOR + <*> fromCBOR + <*> fromCBOR + <*> fromCBOR + slotsPerKESPeriod :: Natural slotsPerKESPeriod = 90 diff --git a/shelley/chain-and-ledger/executable-spec/src/PParams.hs b/shelley/chain-and-ledger/executable-spec/src/PParams.hs index e129ccd8557..7b3665b473c 100644 --- a/shelley/chain-and-ledger/executable-spec/src/PParams.hs +++ b/shelley/chain-and-ledger/executable-spec/src/PParams.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TemplateHaskell #-} module PParams @@ -26,6 +27,8 @@ module PParams , protocolVersion ) where +import Cardano.Prelude (NoUnexpectedThunks(..)) +import GHC.Generics (Generic) import Numeric.Natural (Natural) import BaseTypes (Nonce(NeutralNonce), UnitInterval, interval0) @@ -75,7 +78,9 @@ data PParams = PParams , _extraEntropy :: Nonce -- | Protocol version , _protocolVersion :: (Natural, Natural, Natural) - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks PParams makeLenses ''PParams diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Avup.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Avup.hs index 78b45d7ebfc..6aff73e0d5e 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Avup.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Avup.hs @@ -30,7 +30,7 @@ data AVUPState hashAlgo dsignAlgo (Applications hashAlgo) data AVUPEnv hashAlgo dsignAlgo - = AVUPEnv Slot (Dms hashAlgo dsignAlgo) + = AVUPEnv Slot (GenDelegs hashAlgo dsignAlgo) instance STS (AVUP hashAlgo dsignAlgo) where type State (AVUP hashAlgo dsignAlgo) @@ -62,12 +62,12 @@ avUpdateEmpty = do avUpdateNoConsensus :: TransitionRule (AVUP hashAlgo dsignAlgo) avUpdateNoConsensus = do - TRC (AVUPEnv _slot (Dms _dms), AVUPState (AVUpdate aupS) favs avs, AVUpdate _aup) <- + TRC (AVUPEnv _slot (GenDelegs _genDelegs), AVUPState (AVUpdate aupS) favs avs, AVUpdate _aup) <- judgmentContext not (Map.null _aup) ?! EmptyAVUP - dom _aup ⊆ dom _dms ?! NonGenesisUpdateAVUP + dom _aup ⊆ dom _genDelegs ?! NonGenesisUpdateAVUP all allApNamesValid (range _aup) ?! InvalidName @@ -84,12 +84,12 @@ avUpdateNoConsensus = do avUpdateConsensus :: TransitionRule (AVUP hashAlgo dsignAlgo) avUpdateConsensus = do - TRC (AVUPEnv _slot (Dms _dms), AVUPState (AVUpdate aupS) favs avs, AVUpdate _aup) <- + TRC (AVUPEnv _slot (GenDelegs _genDelegs), AVUPState (AVUpdate aupS) favs avs, AVUpdate _aup) <- judgmentContext not (Map.null _aup) ?! EmptyAVUP - dom _aup ⊆ dom _dms ?! NonGenesisUpdateAVUP + dom _aup ⊆ dom _genDelegs ?! NonGenesisUpdateAVUP all allApNamesValid (range _aup) ?! InvalidName diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Bbody.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Bbody.hs index d6b44f5f60c..c8172c2e825 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Bbody.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Bbody.hs @@ -10,13 +10,16 @@ module STS.Bbody ( BBODY , BbodyState (..) , BbodyEnv (..) + , PredicateFailure(..) ) where import Data.Set (Set) -import BlockChain import Control.State.Transition + +import BlockChain +import Coin (Coin) import EpochBoundary import Keys import Ledger.Core ((∈)) @@ -32,7 +35,11 @@ data BbodyState hashAlgo dsignAlgo vrfAlgo = BbodyState (LedgerState hashAlgo dsignAlgo vrfAlgo) (BlocksMade hashAlgo dsignAlgo) data BbodyEnv - = BbodyEnv (Set Slot) PParams + = BbodyEnv + { bbodySlots :: (Set Slot) + , bbodyPp :: PParams + , bbodyReserves :: Coin + } instance ( HashAlgorithm hashAlgo @@ -68,7 +75,7 @@ bbodyTransition ) => TransitionRule (BBODY hashAlgo dsignAlgo kesAlgo vrfAlgo) bbodyTransition = do - TRC ( BbodyEnv oslots pp + TRC ( BbodyEnv oslots pp _reserves , BbodyState ls b , Block (BHeader bhb _) txsSeq@(TxSeq txs)) <- judgmentContext let hk = hashKey $ bvkcold bhb @@ -78,7 +85,7 @@ bbodyTransition = do bhbHash txsSeq == bhash bhb ?! InvalidBodyHashBBODY ls' <- trans @(LEDGERS hashAlgo dsignAlgo vrfAlgo) - $ TRC (LedgersEnv (bheaderSlot bhb) pp, ls, txs) + $ TRC (LedgersEnv (bheaderSlot bhb) pp _reserves, ls, txs) pure $ BbodyState ls' (incrBlocks (bheaderSlot bhb ∈ oslots) hk b) diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Chain.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Chain.hs index 32a2003250b..2171575f079 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Chain.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Chain.hs @@ -9,6 +9,7 @@ module STS.Chain ( CHAIN , ChainState (..) + , PredicateFailure(..) , totalAda ) where @@ -38,11 +39,12 @@ data CHAIN hashAlgo dsignAlgo kesAlgo vrfAlgo data ChainState hashAlgo dsignAlgo kesAlgo vrfAlgo = ChainState - (NewEpochState hashAlgo dsignAlgo vrfAlgo) - Nonce - Nonce - (HashHeader hashAlgo dsignAlgo kesAlgo vrfAlgo) - Slot + { chainNes :: NewEpochState hashAlgo dsignAlgo vrfAlgo + , chainEvolvingNonce :: Nonce + , chainCandidateNonce :: Nonce + , chainHashHeader :: HashHeader hashAlgo dsignAlgo kesAlgo vrfAlgo + , chainSlot :: Slot + } deriving (Show, Eq) instance @@ -94,15 +96,17 @@ chainTransition = do trans @(BHEAD hashAlgo dsignAlgo kesAlgo vrfAlgo) $ TRC (BheadEnv etaC gkeys, nes, bh) let NewEpochState _ eta0 _ bcur es _ _pd osched = nes' - let EpochState _ _ ls pp = es - let LedgerState _ (DPState (DState _ _ _ _ _ _dms) (PState _ _ _ cs)) _ = ls + let EpochState (AccountState _ _reserves) _ ls pp = es + let LedgerState _ (DPState (DState _ _ _ _ _ _genDelegs _) (PState _ _ _ cs)) _ = ls PrtclState cs' h' sL' etaV' etaC' <- trans @(PRTCL hashAlgo dsignAlgo kesAlgo vrfAlgo) - $ TRC (PrtclEnv (OverlayEnv pp osched eta0 _pd _dms) sNow, PrtclState cs h sL etaV etaC, bh) + $ TRC ( PrtclEnv (OverlayEnv pp osched eta0 _pd _genDelegs) sNow + , PrtclState cs h sL etaV etaC + , bh) let ls' = setIssueNumbers ls cs' BbodyState ls'' bcur' <- trans @(BBODY hashAlgo dsignAlgo kesAlgo vrfAlgo) - $ TRC (BbodyEnv (Map.keysSet osched) pp, BbodyState ls' bcur, block) + $ TRC (BbodyEnv (Map.keysSet osched) pp _reserves, BbodyState ls' bcur, block) let nes'' = updateNES nes' bcur' ls'' diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Deleg.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Deleg.hs index 5dca7bde7dd..b58b977b821 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Deleg.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Deleg.hs @@ -4,6 +4,7 @@ module STS.Deleg ( DELEG , DelegEnv (..) + , PredicateFailure(..) ) where @@ -27,7 +28,11 @@ import Hedgehog (Gen) data DELEG hashAlgo dsignAlgo vrfAlgo data DelegEnv - = DelegEnv Slot Ptr + = DelegEnv + { slot :: Slot + , ptr :: Ptr + , reserves :: Coin + } deriving (Show, Eq) instance STS (DELEG hashAlgo dsignAlgo vrfAlgo) @@ -43,6 +48,7 @@ instance STS (DELEG hashAlgo dsignAlgo vrfAlgo) | WrongCertificateTypeDELEG | GenesisKeyNotInpMappingDELEG | DuplicateGenesisDelegateDELEG + | InsufficientForInstantaneousRewardsDELEG deriving (Show, Eq) initialRules = [pure emptyDState] @@ -51,45 +57,53 @@ instance STS (DELEG hashAlgo dsignAlgo vrfAlgo) delegationTransition :: TransitionRule (DELEG hashAlgo dsignAlgo vrfAlgo) delegationTransition = do - TRC (DelegEnv slot_ ptr_, ds, c) <- judgmentContext + TRC (DelegEnv slot_ ptr_ reserves_, ds, c) <- judgmentContext case c of RegKey key -> do - key ∉ dom (_stKeys ds) ?! StakeKeyAlreadyRegisteredDELEG + key ∉ dom (_stkCreds ds) ?! StakeKeyAlreadyRegisteredDELEG pure $ ds - { _stKeys = _stKeys ds ∪ singleton key slot_ + { _stkCreds = _stkCreds ds ∪ singleton key slot_ , _rewards = _rewards ds ∪ Map.singleton (RewardAcnt key) (Coin 0) , _ptrs = _ptrs ds ∪ Map.singleton ptr_ key } DeRegKey key -> do - key ∈ dom (_stKeys ds) ?! StakeKeyNotRegisteredDELEG + key ∈ dom (_stkCreds ds) ?! StakeKeyNotRegisteredDELEG let rewardCoin = Map.lookup (RewardAcnt key) (_rewards ds) rewardCoin == Just 0 ?! StakeKeyNonZeroAccountBalanceDELEG pure $ ds - { _stKeys = Set.singleton key ⋪ _stKeys ds + { _stkCreds = Set.singleton key ⋪ _stkCreds ds , _rewards = Set.singleton (RewardAcnt key) ⋪ _rewards ds , _delegations = Set.singleton key ⋪ _delegations ds , _ptrs = _ptrs ds ⋫ Set.singleton key } Delegate (Delegation delegator_ delegatee_) -> do - delegator_ ∈ dom (_stKeys ds) ?! StakeDelegationImpossibleDELEG + delegator_ ∈ dom (_stkCreds ds) ?! StakeDelegationImpossibleDELEG pure $ ds { _delegations = _delegations ds ⨃ [(delegator_, delegatee_)] } GenesisDelegate (gkey, vk) -> do let s' = slot_ +* slotsPrior - (Dms dms_) = _dms ds + (GenDelegs genDelegs_) = _genDelegs ds - gkey ∈ dom dms_ ?! GenesisKeyNotInpMappingDELEG - vk ∉ range dms_ ?! DuplicateGenesisDelegateDELEG + gkey ∈ dom genDelegs_ ?! GenesisKeyNotInpMappingDELEG + vk ∉ range genDelegs_ ?! DuplicateGenesisDelegateDELEG pure $ ds - { _fdms = _fdms ds ⨃ [((s', gkey), vk)]} + { _fGenDelegs = _fGenDelegs ds ⨃ [((s', gkey), vk)]} + + InstantaneousRewards credCoinMap -> do + let combinedMap = Map.union credCoinMap (_irwd ds) + requiredForRewards = foldl (+) (Coin 0) (range combinedMap) + + requiredForRewards <= reserves_ ?! InsufficientForInstantaneousRewardsDELEG + + pure $ ds { _irwd = combinedMap } _ -> do failBecause WrongCertificateTypeDELEG -- this always fails diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Delegs.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Delegs.hs index 35f781e23d1..99a847ffc77 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Delegs.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Delegs.hs @@ -7,6 +7,7 @@ module STS.Delegs ( DELEGS , DelegsEnv (..) + , PredicateFailure(..) ) where @@ -14,6 +15,7 @@ import qualified Data.Set as Set import Data.Sequence (Seq (..)) +import Coin (Coin) import Delegation.Certificates import Keys import LedgerState @@ -34,7 +36,13 @@ import Hedgehog (Gen) data DELEGS hashAlgo dsignAlgo vrfAlgo data DelegsEnv hashAlgo dsignAlgo vrfAlgo - = DelegsEnv Slot Ix PParams (Tx hashAlgo dsignAlgo vrfAlgo) + = DelegsEnv + { delegsSlot :: Slot + , delegsIx :: Ix + , delegspp :: PParams + , delegsTx :: (Tx hashAlgo dsignAlgo vrfAlgo) + , delegsReserves :: Coin + } deriving Show instance @@ -58,7 +66,7 @@ delegsTransition . (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => TransitionRule (DELEGS hashAlgo dsignAlgo vrfAlgo) delegsTransition = do - TRC (env@(DelegsEnv _slot txIx pp (Tx txbody _ _)), dpstate, certificates) <- judgmentContext + TRC (env@(DelegsEnv _slot txIx pp (Tx txbody _ _) _reserves), dpstate, certificates) <- judgmentContext case certificates of Empty -> do @@ -87,7 +95,7 @@ delegsTransition = do isDelegationRegistered ?! DelegateeNotRegisteredDELEG trans @(DELPL hashAlgo dsignAlgo vrfAlgo) - $ TRC (DelplEnv _slot ptr pp, dpstate', cert) + $ TRC (DelplEnv _slot ptr pp _reserves, dpstate', cert) instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Delpl.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Delpl.hs index ae17e60c305..db1b930eb34 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Delpl.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Delpl.hs @@ -7,9 +7,11 @@ module STS.Delpl ( DELPL , DelplEnv (..) + , PredicateFailure(..) ) where +import Coin (Coin) import Delegation.Certificates import Keys import LedgerState @@ -25,7 +27,12 @@ import STS.Pool data DELPL hashAlgo dsignAlgo vrfAlgo data DelplEnv - = DelplEnv Slot Ptr PParams + = DelplEnv + { delplSlot :: Slot + , delPlPtr :: Ptr + , delPlPp :: PParams + , delPlReserves :: Coin + } instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) @@ -50,7 +57,7 @@ delplTransition . (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => TransitionRule (DELPL hashAlgo dsignAlgo vrfAlgo) delplTransition = do - TRC (DelplEnv slotIx ptr pp, d, c) <- judgmentContext + TRC (DelplEnv slotIx _ptr pp _reserves, d, c) <- judgmentContext case c of RegPool _ -> do ps <- @@ -62,24 +69,29 @@ delplTransition = do pure $ d { _pstate = ps } GenesisDelegate _ -> do ds <- - trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx ptr, _dstate d, c) + trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx _ptr _reserves, _dstate d, c) pure $ d { _dstate = ds } RegKey _ -> do ds <- - trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx ptr, _dstate d, c) + trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx _ptr _reserves, _dstate d, c) pure $ d { _dstate = ds } DeRegKey _ -> do ds <- - trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx ptr, _dstate d, c) + trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx _ptr _reserves, _dstate d, c) pure $ d { _dstate = ds } Delegate _ -> do ds <- - trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx ptr, _dstate d, c) + trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx _ptr _reserves , _dstate d, c) pure $ d { _dstate = ds } + InstantaneousRewards _ -> do + ds <- trans @(DELEG hashAlgo dsignAlgo vrfAlgo) $ TRC (DelegEnv slotIx _ptr _reserves , _dstate d, c) + pure $ d { _dstate = ds } + + instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => Embed (POOL hashAlgo dsignAlgo vrfAlgo) (DELPL hashAlgo dsignAlgo vrfAlgo) diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Ledger.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Ledger.hs index 23e3b5b0e87..a5acedc30ad 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Ledger.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Ledger.hs @@ -9,11 +9,13 @@ module STS.Ledger ( LEDGER , LedgerEnv (..) + , PredicateFailure(..) ) where import Lens.Micro ((^.)) +import Coin (Coin) import Control.State.Transition import Keys import LedgerState @@ -27,7 +29,12 @@ import Tx data LEDGER hashAlgo dsignAlgo vrfAlgo data LedgerEnv - = LedgerEnv Slot Ix PParams + = LedgerEnv + { ledgerSlot :: Slot + , ledgerIx :: Ix + , ledgerPp :: PParams + , ledgerReserves :: Coin + } deriving (Show) instance @@ -59,15 +66,15 @@ ledgerTransition ) => TransitionRule (LEDGER hashAlgo dsignAlgo vrfAlgo) ledgerTransition = do - TRC (LedgerEnv slot ix pp, (u, d), tx) <- judgmentContext + TRC (LedgerEnv slot ix pp _reserves, (u, d), tx) <- judgmentContext utxo' <- trans @(UTXOW hashAlgo dsignAlgo vrfAlgo) $ TRC - ( UtxoEnv slot pp (d ^. dstate . stKeys) (d ^. pstate . stPools) (d ^. dstate . dms) + ( UtxoEnv slot pp (d ^. dstate . stkCreds) (d ^. pstate . stPools) (d ^. dstate . genDelegs) , u , tx ) deleg' <- trans @(DELEGS hashAlgo dsignAlgo vrfAlgo) - $ TRC (DelegsEnv slot ix pp tx, d, tx ^. body . certs) + $ TRC (DelegsEnv slot ix pp tx _reserves, d, tx ^. body . certs) pure (utxo', deleg') instance diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Ledgers.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Ledgers.hs index 9ab11ab353a..45dfbb863b1 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Ledgers.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Ledgers.hs @@ -9,6 +9,7 @@ module STS.Ledgers ( LEDGERS , LedgersEnv (..) + , PredicateFailure(..) ) where @@ -19,6 +20,8 @@ import Data.Sequence (Seq) import qualified Data.Set as Set import Control.State.Transition + +import Coin (Coin) import Keys import Ledger.Core (dom, range, (⋪), (◁), (⨃)) import LedgerState @@ -31,7 +34,11 @@ import Updates (Applications (..), UpdateState (..), apps, newAVs) data LEDGERS hashAlgo dsignAlgo vrfAlgo data LedgersEnv - = LedgersEnv Slot PParams + = LedgersEnv + { ledgersSlot :: Slot + , ledgersPp :: PParams + , ledgersReserves :: Coin + } instance ( HashAlgorithm hashAlgo @@ -60,13 +67,13 @@ ledgersTransition ) => TransitionRule (LEDGERS hashAlgo dsignAlgo vrfAlgo) ledgersTransition = do - TRC (LedgersEnv slot pp, ls, txwits) <- judgmentContext + TRC (LedgersEnv slot pp _reserves, ls, txwits) <- judgmentContext let (u, dw) = (_utxoState ls, _delegationState ls) (u'', dw'') <- foldM (\(u', dw') (ix, tx) -> trans @(LEDGER hashAlgo dsignAlgo vrfAlgo) - $ TRC (LedgerEnv slot ix pp, (u', dw'), tx) + $ TRC (LedgerEnv slot ix pp _reserves, (u', dw'), tx) ) (u, dw) $ zip [0 ..] $ toList txwits @@ -78,21 +85,21 @@ ledgersTransition = do let ds = _dstate dw'' ps = _pstate dw'' - fdms_ = _fdms ds - Dms dms_ = _dms ds - (curr, fdms') = Map.partitionWithKey (\(s, _) _ -> s <= slot) fdms_ + fGenDelegs_ = _fGenDelegs ds + GenDelegs genDelegs_ = _genDelegs ds + (curr, fGenDelegs') = Map.partitionWithKey (\(s, _) _ -> s <= slot) fGenDelegs_ let maxSlot = maximum . Set.map fst . Map.keysSet let latestPerGKey gk = ( (maxSlot . Map.filterWithKey (\(_, c) _ -> c == gk)) curr , gk) - let dmsKeys = Set.map + let genDelegsKeys = Set.map latestPerGKey (Set.map snd (Map.keysSet curr)) - let dms' = Map.mapKeys snd $ dmsKeys ◁ curr - let oldGenDelegs = range (dom dms' ◁ dms_) - let cs' = (oldGenDelegs ⋪ _cCounters ps) ⨃ fmap (\x -> (x, 0)) (Map.elems dms') - let dw''' = dw'' { _dstate = ds { _fdms = fdms' - , _dms = Dms $ dms_ ⨃ Map.toList dms'} + let genDelegs' = Map.mapKeys snd $ genDelegsKeys ◁ curr + let oldGenDelegs = range (dom genDelegs' ◁ genDelegs_) + let cs' = (oldGenDelegs ⋪ _cCounters ps) ⨃ fmap (\x -> (x, 0)) (Map.elems genDelegs') + let dw''' = dw'' { _dstate = ds { _fGenDelegs = fGenDelegs' + , _genDelegs = GenDelegs $ genDelegs_ ⨃ Map.toList genDelegs'} , _pstate = ps { _cCounters = cs' } } diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/NewEpoch.hs b/shelley/chain-and-ledger/executable-spec/src/STS/NewEpoch.hs index d8d9d2b49f9..6e61983945d 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/NewEpoch.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/NewEpoch.hs @@ -67,7 +67,7 @@ newEpochTransition = do else do let es_ = case ru of Nothing -> es - Just ru' -> applyRUpd ru' es + Just ru' -> applyRUpd ru' e es es' <- trans @(EPOCH hashAlgo dsignAlgo vrfAlgo) $ TRC ((), es_, e) let EpochState acnt ss ls pp = es' diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Newpp.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Newpp.hs index 2c1d3457085..2acc3602e48 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Newpp.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Newpp.hs @@ -1,4 +1,6 @@ +{-# LANGUAGE DataKinds #-} {-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TypeFamilies #-} module STS.Newpp @@ -14,7 +16,8 @@ import Lens.Micro ((^.)) import Coin import EpochBoundary -import LedgerState hiding (reserves) +import LedgerState (AccountState, DState, PState, UTxOState, pattern UTxOState, clearPpup, + emptyAccount, stkCreds, stPools, _deposited, _irwd, _reserves) import PParams import Slot import Updates @@ -54,12 +57,13 @@ newPpTransition = do case ppNew of Just ppNew' -> do let slot_ = firstSlot e - Coin oblgCurr = obligation pp (ds ^. stKeys) (ps ^. stPools) slot_ - Coin oblgNew = obligation ppNew' (ds ^. stKeys) (ps ^. stPools) slot_ + Coin oblgCurr = obligation pp (ds ^. stkCreds) (ps ^. stPools) slot_ + Coin oblgNew = obligation ppNew' (ds ^. stkCreds) (ps ^. stPools) slot_ diff = oblgCurr - oblgNew + Coin reserves = _reserves acnt + Coin requiredInstantaneousRewards = foldl (+) (Coin 0) $ _irwd ds - let Coin reserves = _reserves acnt - if reserves + diff >= 0 + if reserves + diff >= requiredInstantaneousRewards && (_maxTxSize ppNew' + _maxBHSize ppNew') < _maxBBSize ppNew' then let utxoSt' = utxoSt { _deposited = Coin oblgNew } diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Overlay.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Overlay.hs index b27f1559a3a..1bc8c37ddde 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Overlay.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Overlay.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -15,6 +16,7 @@ where import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Numeric.Natural (Natural) +import GHC.Generics (Generic) import BaseTypes import BlockChain @@ -27,6 +29,7 @@ import Slot import STS.Ocert import qualified Cardano.Crypto.VRF as VRF +import Cardano.Prelude (NoUnexpectedThunks(..)) import Control.State.Transition data OVERLAY hashAlgo dsignAlgo kesAlgo vrfAlgo @@ -37,7 +40,10 @@ data OverlayEnv hashAlgo dsignAlgo kesAlgo vrfAlgo (Map Slot (Maybe (GenKeyHash hashAlgo dsignAlgo))) Nonce (PoolDistr hashAlgo dsignAlgo vrfAlgo) - (Dms hashAlgo dsignAlgo) + (GenDelegs hashAlgo dsignAlgo) + deriving Generic + +instance NoUnexpectedThunks (OverlayEnv hashAlgo dsignAlgo kesAlgo vrfAlgo) instance ( HashAlgorithm hashAlgo @@ -82,7 +88,7 @@ overlayTransition ) => TransitionRule (OVERLAY hashAlgo dsignAlgo kesAlgo vrfAlgo) overlayTransition = do - TRC ( OverlayEnv pp osched eta0 pd (Dms dms) + TRC ( OverlayEnv pp osched eta0 pd (GenDelegs genDelegs) , cs , bh@(BHeader bhb _)) <- judgmentContext let vk = bvkcold bhb @@ -94,11 +100,11 @@ overlayTransition = do Just Nothing -> failBecause NotActiveSlotOVERLAY Just (Just gkey) -> - case Map.lookup gkey dms of + case Map.lookup gkey genDelegs of Nothing -> failBecause NoGenesisStakingOVERLAY - Just dmsKey -> - vkh == dmsKey ?! WrongGenesisColdKeyOVERLAY vkh dmsKey + Just genDelegsKey -> + vkh == genDelegsKey ?! WrongGenesisColdKeyOVERLAY vkh genDelegsKey trans @(OCERT hashAlgo dsignAlgo kesAlgo vrfAlgo) $ TRC ((), cs, bh) diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Ppup.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Ppup.hs index d7ef8bb3695..f7006f9cac9 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Ppup.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Ppup.hs @@ -26,7 +26,7 @@ import Numeric.Natural (Natural) data PPUP hashAlgo dsignAlgo data PPUPEnv hashAlgo dsignAlgo - = PPUPEnv Slot PParams (Dms hashAlgo dsignAlgo) + = PPUPEnv Slot PParams (GenDelegs hashAlgo dsignAlgo) instance STS (PPUP hashAlgo dsignAlgo) where type State (PPUP hashAlgo dsignAlgo) = PPUpdate hashAlgo dsignAlgo @@ -62,13 +62,13 @@ ppupTransitionEmpty = do ppupTransitionNonEmpty :: TransitionRule (PPUP hashAlgo dsignAlgo) ppupTransitionNonEmpty = do - TRC (PPUPEnv s pp (Dms _dms), pupS, pup@(PPUpdate pup')) <- judgmentContext + TRC (PPUPEnv s pp (GenDelegs _genDelegs), pupS, pup@(PPUpdate pup')) <- judgmentContext pup' /= Map.empty ?! PPUpdateEmpty all (all (pvCanFollow (_protocolVersion pp))) pup' ?! PVCannotFollowPPUP - (dom pup' ⊆ dom _dms) ?! NonGenesisUpdatePPUP (dom pup') (dom _dms) + (dom pup' ⊆ dom _genDelegs) ?! NonGenesisUpdatePPUP (dom pup') (dom _genDelegs) let Epoch slotEpoch = epochFromSlot (Slot 1) s diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Prtcl.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Prtcl.hs index 8140be13478..958b5244193 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Prtcl.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Prtcl.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -16,6 +17,7 @@ module STS.Prtcl where import Data.Map.Strict (Map) +import GHC.Generics (Generic) import Numeric.Natural (Natural) import BaseTypes @@ -28,6 +30,7 @@ import STS.Overlay import STS.Updn import qualified Cardano.Crypto.VRF as VRF +import Cardano.Prelude (NoUnexpectedThunks(..)) import Control.State.Transition data PRTCL hashAlgo dsignAlgo kesAlgo vrfAlgo @@ -39,9 +42,15 @@ data PrtclState hashAlgo dsignAlgo kesAlgo vrfAlgo Slot Nonce Nonce + deriving (Generic, Show) + +instance NoUnexpectedThunks (PrtclState hashAlgo dsignAlgo kesAlgo vrfAlgo) data PrtclEnv hashAlgo dsignAlgo kesAlgo vrfAlgo = PrtclEnv (OverlayEnv hashAlgo dsignAlgo kesAlgo vrfAlgo) Slot + deriving (Generic) + +instance NoUnexpectedThunks (PrtclEnv hashAlgo dsignAlgo kesAlgo vrfAlgo) instance ( HashAlgorithm hashAlgo diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Snap.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Snap.hs index ed3c43689ce..f4575003df8 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Snap.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Snap.hs @@ -52,7 +52,7 @@ snapTransition = do TRC (SnapEnv pparams d p, SnapState s u, eNew) <- judgmentContext let pooledStake = stakeDistr (u ^. utxo) d p let _slot = firstSlot eNew - let oblg = obligation pparams (d ^. stKeys) (p ^. stPools) _slot + let oblg = obligation pparams (d ^. stkCreds) (p ^. stPools) _slot let decayed = (u ^. deposited) - oblg pure $ SnapState s { _pstakeMark = pooledStake diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Up.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Up.hs index de66b1c6fc0..9282dd092ea 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Up.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Up.hs @@ -23,7 +23,7 @@ import STS.Ppup data UP hashAlgo dsignAlgo data UpdateEnv hashAlgo dsignAlgo - = UpdateEnv Slot PParams (Dms hashAlgo dsignAlgo) + = UpdateEnv Slot PParams (GenDelegs hashAlgo dsignAlgo) instance DSIGNAlgorithm dsignAlgo => STS (UP hashAlgo dsignAlgo) where type State (UP hashAlgo dsignAlgo) = UpdateState hashAlgo dsignAlgo @@ -43,11 +43,13 @@ upTransition . DSIGNAlgorithm dsignAlgo => TransitionRule (UP hashAlgo dsignAlgo) upTransition = do - TRC (UpdateEnv _slot pp _dms, UpdateState pupS aupS favs avs, Update pup _aup) <- judgmentContext + TRC ( UpdateEnv _slot pp _genDelegs + , UpdateState pupS aupS favs avs + , Update pup _aup) <- judgmentContext - pup' <- trans @(PPUP hashAlgo dsignAlgo) $ TRC (PPUPEnv _slot pp _dms, pupS, pup) + pup' <- trans @(PPUP hashAlgo dsignAlgo) $ TRC (PPUPEnv _slot pp _genDelegs, pupS, pup) AVUPState aup' favs' avs' <- - trans @(AVUP hashAlgo dsignAlgo) $ TRC (AVUPEnv _slot _dms, AVUPState aupS favs avs, _aup) + trans @(AVUP hashAlgo dsignAlgo) $ TRC (AVUPEnv _slot _genDelegs, AVUPState aupS favs avs, _aup) pure $ UpdateState pup' aup' favs' avs' diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Utxo.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Utxo.hs index 3888e157efb..760ca6eea71 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Utxo.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Utxo.hs @@ -43,9 +43,9 @@ data UtxoEnv hashAlgo dsignAlgo = UtxoEnv Slot PParams - (StakeKeys hashAlgo dsignAlgo) + (StakeCreds hashAlgo dsignAlgo) (StakePools hashAlgo dsignAlgo) - (Dms hashAlgo dsignAlgo) + (GenDelegs hashAlgo dsignAlgo) deriving(Show) instance @@ -82,7 +82,7 @@ utxoInductive . (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo, VRFAlgorithm vrfAlgo) => TransitionRule (UTXO hashAlgo dsignAlgo vrfAlgo) utxoInductive = do - TRC (UtxoEnv slot_ pp stakeKeys stakePools dms_, u, tx) <- judgmentContext + TRC (UtxoEnv slot_ pp stakeKeys stakePools genDelegs_, u, tx) <- judgmentContext let txBody = _body tx _ttl txBody >= slot_ ?! ExpiredUTxO (_ttl txBody) slot_ @@ -100,7 +100,7 @@ utxoInductive = do consumed_ == produced_ ?! ValueNotConservedUTxO consumed_ produced_ -- process Update Proposals - ups' <- trans @(UP hashAlgo dsignAlgo) $ TRC (UpdateEnv slot_ pp dms_, u ^. ups, txup tx) + ups' <- trans @(UP hashAlgo dsignAlgo) $ TRC (UpdateEnv slot_ pp genDelegs_, u ^. ups, txup tx) let outputCoins = [c | (TxOut _ c) <- Set.toList (range (txouts txBody))] all (0 <=) outputCoins ?! NegativeOutputsUTxO diff --git a/shelley/chain-and-ledger/executable-spec/src/STS/Utxow.hs b/shelley/chain-and-ledger/executable-spec/src/STS/Utxow.hs index a11cf8f55f7..641a8094044 100644 --- a/shelley/chain-and-ledger/executable-spec/src/STS/Utxow.hs +++ b/shelley/chain-and-ledger/executable-spec/src/STS/Utxow.hs @@ -13,10 +13,15 @@ module STS.Utxow where import qualified Data.Map.Strict as Map +import qualified Data.Sequence as Seq (filter) import qualified Data.Set as Set +import BaseTypes (intervalValue, (==>)) +import Delegation.Certificates (isInstantaneousRewards) import Keys -import LedgerState hiding (dms) +import Ledger.Core (dom, (∩)) +import LedgerState hiding (genDelegs) +import PParams (_d) import STS.Utxo import Tx import TxData @@ -46,6 +51,8 @@ instance | MissingScriptWitnessesUTXOW | ScriptWitnessNotValidatingUTXOW | UtxoFailure (PredicateFailure (UTXO hashAlgo dsignAlgo vrfAlgo)) + | MIRInsufficientGenesisSigsUTXOW + | MIRImpossibleInDecentralizedNetUTXOW deriving (Eq, Show) transitionRules = [utxoWitnessed] @@ -60,8 +67,8 @@ initialLedgerStateUTXOW ) => InitialRule (UTXOW hashAlgo dsignAlgo vrfAlgo) initialLedgerStateUTXOW = do - IRC (UtxoEnv slots pp stakeKeys stakePools dms) <- judgmentContext - trans @(UTXO hashAlgo dsignAlgo vrfAlgo) $ IRC (UtxoEnv slots pp stakeKeys stakePools dms) + IRC (UtxoEnv slots pp stakeKeys stakePools genDelegs) <- judgmentContext + trans @(UTXO hashAlgo dsignAlgo vrfAlgo) $ IRC (UtxoEnv slots pp stakeKeys stakePools genDelegs) utxoWitnessed :: forall hashAlgo dsignAlgo vrfAlgo @@ -72,11 +79,11 @@ utxoWitnessed ) => TransitionRule (UTXOW hashAlgo dsignAlgo vrfAlgo) utxoWitnessed = do - TRC (UtxoEnv slot pp stakeKeys stakePools _dms, u, tx@(Tx _ wits _)) + TRC (UtxoEnv slot pp stakeKeys stakePools _genDelegs, u, tx@(Tx txbody wits _)) <- judgmentContext verifiedWits tx == Valid ?! InvalidWitnessesUTXOW let witnessKeys = Set.map witKeyHash wits - let needed = witsVKeyNeeded (_utxo u) tx _dms + let needed = witsVKeyNeeded (_utxo u) tx _genDelegs needed `Set.isSubsetOf` witnessKeys ?! MissingVKeyWitnessesUTXOW -- check multi-signature scripts @@ -89,8 +96,19 @@ utxoWitnessed = do scriptsNeeded utxo' tx == Map.keysSet (txwitsScript tx) ?! MissingScriptWitnessesUTXOW + -- check genesis keys signatures for instantaneous rewards certificates + let mirCerts = Seq.filter isInstantaneousRewards $ _certs txbody + GenDelegs genMapping = _genDelegs + genSig = (Set.map undiscriminateKeyHash $ dom genMapping) ∩ Set.map witKeyHash wits + ( (not $ null mirCerts) + ==> Set.size genSig >= 5) + ?! MIRInsufficientGenesisSigsUTXOW + ( (not $ null mirCerts) + ==> (0 < intervalValue (_d pp))) + ?! MIRImpossibleInDecentralizedNetUTXOW + trans @(UTXO hashAlgo dsignAlgo vrfAlgo) - $ TRC (UtxoEnv slot pp stakeKeys stakePools _dms, u, tx) + $ TRC (UtxoEnv slot pp stakeKeys stakePools _genDelegs, u, tx) instance ( HashAlgorithm hashAlgo diff --git a/shelley/chain-and-ledger/executable-spec/src/Slot.hs b/shelley/chain-and-ledger/executable-spec/src/Slot.hs index 05d44c988e1..0985a37cc02 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Slot.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Slot.hs @@ -20,12 +20,13 @@ module Slot import Numeric.Natural (Natural) import Cardano.Binary (ToCBOR) +import Cardano.Prelude (NoUnexpectedThunks(..)) import qualified Ledger.Core as Byron (Slot (..)) -- |A Slot newtype Slot = Slot Natural - deriving (Show, Eq, Ord, Num, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, Num, ToCBOR) instance Semigroup Slot where (Slot x) <> (Slot y) = Slot $ x + y @@ -35,7 +36,7 @@ instance Monoid Slot where mappend = (<>) newtype Duration = Duration Natural - deriving (Show, Eq, Ord, Num, Integral, Real, Enum) + deriving (Show, Eq, Ord, NoUnexpectedThunks, Num, Integral, Real, Enum) instance Semigroup Duration where (Duration x) <> (Duration y) = Duration $ x + y @@ -56,7 +57,7 @@ instance Monoid Duration where -- |An Epoch newtype Epoch = Epoch Natural - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, NoUnexpectedThunks, Ord, ToCBOR) instance Semigroup Epoch where (Epoch x) <> (Epoch y) = Epoch $ x + y diff --git a/shelley/chain-and-ledger/executable-spec/src/TxData.hs b/shelley/chain-and-ledger/executable-spec/src/TxData.hs index 646ed697444..8e9a0a9ad99 100644 --- a/shelley/chain-and-ledger/executable-spec/src/TxData.hs +++ b/shelley/chain-and-ledger/executable-spec/src/TxData.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE PatternSynonyms #-} @@ -12,6 +13,7 @@ module TxData import Cardano.Binary (FromCBOR (fromCBOR), ToCBOR (toCBOR), decodeListLen, decodeWord, encodeListLen, encodeWord) +import Cardano.Prelude (NoUnexpectedThunks (..)) import Lens.Micro.TH (makeLenses) @@ -23,13 +25,14 @@ import Data.Sequence (Seq) import Data.Set (Set) import Data.Typeable (Typeable) import Data.Word (Word8) +import GHC.Generics (Generic) import Numeric.Natural (Natural) import BaseTypes (UnitInterval) import Coin (Coin) import Keys (AnyKeyHash, pattern AnyKeyHash, DSIGNAlgorithm, GenKeyHash, Hash, - HashAlgorithm, KeyHash, Sig, VKey, VKeyGenesis, hashAnyKey - , VRFAlgorithm(VerKeyVRF)) + HashAlgorithm, KeyHash, Sig, VKey, VKeyGenesis, VRFAlgorithm (VerKeyVRF), + hashAnyKey) import Ledger.Core (Relation (..)) import Slot (Epoch, Slot) import Updates (Update) @@ -38,7 +41,9 @@ import Updates (Update) data Delegation hashAlgo dsignAlgo = Delegation { _delegator :: Credential hashAlgo dsignAlgo , _delegatee :: KeyHash hashAlgo dsignAlgo - } deriving (Eq, Show) + } deriving (Eq, Generic, Show) + +instance NoUnexpectedThunks (Delegation hashAlgo dsignAlgo) -- |A stake pool. data PoolParams hashAlgo dsignAlgo vrfAlgo = @@ -50,19 +55,23 @@ data PoolParams hashAlgo dsignAlgo vrfAlgo = , _poolMargin :: UnitInterval , _poolRAcnt :: RewardAcnt hashAlgo dsignAlgo , _poolOwners :: Set (KeyHash hashAlgo dsignAlgo) - } deriving (Show, Eq) + } deriving (Show, Generic, Eq) + +instance NoUnexpectedThunks (PoolParams hashAlgo dsignAlgo vrfAlgo) -- |An account based address for rewards newtype RewardAcnt hashAlgo signAlgo = RewardAcnt { getRwdCred :: StakeCredential hashAlgo signAlgo - } deriving (Show, Eq, Ord) + } deriving (Show, Eq, NoUnexpectedThunks, Ord) -- | Script hash or key hash for a payment or a staking object. data Credential hashAlgo dsignAlgo = ScriptHashObj { _validatorHash :: ScriptHash hashAlgo dsignAlgo } | KeyHashObj { _vkeyHash :: KeyHash hashAlgo dsignAlgo } | GenesisHashObj { _genKeyHash :: GenKeyHash hashAlgo dsignAlgo } - deriving (Show, Eq, Ord) + deriving (Show, Eq, Generic, Ord) + +instance NoUnexpectedThunks (Credential hashAlgo dsignAlgo) -- |An address for UTxO. data Addr hashAlgo dsignAlgo @@ -76,14 +85,18 @@ data Addr hashAlgo dsignAlgo { _paymentObjP :: Credential hashAlgo dsignAlgo , _stakePtr :: Ptr } - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, Generic) + +instance NoUnexpectedThunks (Addr hashAlgo dsignAlgo) type Ix = Natural -- | Pointer to a slot, transaction index and index in certificate list. data Ptr = Ptr Slot Ix Ix - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, Generic) + +instance NoUnexpectedThunks Ptr -- | A simple language for expressing conditions under which it is valid to -- withdraw from a normal UTxO payment address or to use a stake address. @@ -113,28 +126,34 @@ data MultiSig hashAlgo dsignAlgo = -- | Require M of the given sub-terms to be satisfied. | RequireMOf Int [MultiSig hashAlgo dsignAlgo] - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, Generic) + +instance NoUnexpectedThunks (MultiSig hashAlgo dsignAlgo) newtype ScriptHash hashAlgo dsignAlgo = ScriptHash (Hash hashAlgo (MultiSig hashAlgo dsignAlgo)) - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, ToCBOR) type Wdrl hashAlgo dsignAlgo = Map (RewardAcnt hashAlgo dsignAlgo) Coin -- |A unique ID of a transaction, which is computable from the transaction. newtype TxId hashAlgo dsignAlgo vrfAlgo = TxId { _TxId :: Hash hashAlgo (TxBody hashAlgo dsignAlgo vrfAlgo) } - deriving (Show, Eq, Ord, ToCBOR) + deriving (Show, Eq, Ord, NoUnexpectedThunks, ToCBOR) -- |The input of a UTxO. data TxIn hashAlgo dsignAlgo vrfAlgo = TxIn (TxId hashAlgo dsignAlgo vrfAlgo) Natural - deriving (Show, Eq, Ord) + deriving (Show, Eq, Generic, Ord) + +instance NoUnexpectedThunks (TxIn hashAlgo dsignAlgo vrfAlgo) -- |The output of a UTxO. data TxOut hashAlgo dsignAlgo = TxOut (Addr hashAlgo dsignAlgo) Coin - deriving (Show, Eq, Ord) + deriving (Show, Eq, Generic, Ord) + +instance NoUnexpectedThunks (TxOut hashAlgo dsignAlgo) type StakeCredential hashAlgo dsignAlgo = Credential hashAlgo dsignAlgo @@ -152,7 +171,11 @@ data DCert hashAlgo dsignAlgo vrfAlgo | Delegate (Delegation hashAlgo dsignAlgo) -- | Genesis key delegation certificate | GenesisDelegate (GenKeyHash hashAlgo dsignAlgo, KeyHash hashAlgo dsignAlgo) - deriving (Show, Eq) + -- | Move instantaneous rewards certificate + | InstantaneousRewards (Map (Credential hashAlgo dsignAlgo) Coin) + deriving (Show, Generic, Eq) + +instance NoUnexpectedThunks (DCert hashAlgo dsignAlgo vrfAlgo) -- |A raw transaction data TxBody hashAlgo dsignAlgo vrfAlgo @@ -164,13 +187,18 @@ data TxBody hashAlgo dsignAlgo vrfAlgo , _txfee :: Coin , _ttl :: Slot , _txUpdate :: Update hashAlgo dsignAlgo - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (TxBody hashAlgo dsignAlgo vrfAlgo) -- |Proof/Witness that a transaction is authorized by the given key holder. data WitVKey hashAlgo dsignAlgo vrfAlgo = WitVKey (VKey dsignAlgo) !(Sig dsignAlgo (TxBody hashAlgo dsignAlgo vrfAlgo)) | WitGVKey (VKeyGenesis dsignAlgo) !(Sig dsignAlgo (TxBody hashAlgo dsignAlgo vrfAlgo)) - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance (DSIGNAlgorithm dsignAlgo) + => NoUnexpectedThunks (WitVKey hashAlgo dsignAlgo vrfAlgo) witKeyHash :: forall hashAlgo dsignAlgo vrfAlgo. (DSIGNAlgorithm dsignAlgo, HashAlgorithm hashAlgo) @@ -191,15 +219,18 @@ data Tx hashAlgo dsignAlgo vrfAlgo , _witnessVKeySet :: !(Set (WitVKey hashAlgo dsignAlgo vrfAlgo)) , _witnessMSigMap :: Map (ScriptHash hashAlgo dsignAlgo) (MultiSig hashAlgo dsignAlgo) - } deriving (Show, Eq) + } deriving (Show, Eq, Generic) -newtype StakeKeys hashAlgo dsignAlgo = - StakeKeys (Map (StakeCredential hashAlgo dsignAlgo) Slot) - deriving (Show, Eq) +instance (DSIGNAlgorithm dsignAlgo) + => NoUnexpectedThunks (Tx hashAlgo dsignAlgo vrfAlgo) + +newtype StakeCreds hashAlgo dsignAlgo = + StakeCreds (Map (StakeCredential hashAlgo dsignAlgo) Slot) + deriving (Show, Eq, NoUnexpectedThunks) newtype StakePools hashAlgo dsignAlgo = StakePools (Map (KeyHash hashAlgo dsignAlgo) Slot) - deriving (Show, Eq) + deriving (Show, Eq, NoUnexpectedThunks) -- CBOR @@ -240,6 +271,11 @@ instance <> toCBOR (5 :: Word8) <> toCBOR keys + InstantaneousRewards credCoinMap -> + encodeListLen 2 + <> toCBOR (6 :: Word8) + <> toCBOR credCoinMap + instance (Typeable dsignAlgo, HashAlgorithm hashAlgo, VRFAlgorithm vrfAlgo) => ToCBOR (TxIn hashAlgo dsignAlgo vrfAlgo) @@ -399,35 +435,35 @@ instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) encodeListLen 1 <> toCBOR (getRwdCred rwdAcnt) -instance Relation (StakeKeys hashAlgo dsignAlgo) where - type Domain (StakeKeys hashAlgo dsignAlgo) = StakeCredential hashAlgo dsignAlgo - type Range (StakeKeys hashAlgo dsignAlgo) = Slot +instance Relation (StakeCreds hashAlgo dsignAlgo) where + type Domain (StakeCreds hashAlgo dsignAlgo) = StakeCredential hashAlgo dsignAlgo + type Range (StakeCreds hashAlgo dsignAlgo) = Slot - singleton k v = StakeKeys $ Map.singleton k v + singleton k v = StakeCreds $ Map.singleton k v - dom (StakeKeys stKeys) = dom stKeys + dom (StakeCreds stkCreds) = dom stkCreds - range (StakeKeys stKeys) = range stKeys + range (StakeCreds stkCreds) = range stkCreds - s ◁ (StakeKeys stKeys) = StakeKeys $ s ◁ stKeys + s ◁ (StakeCreds stkCreds) = StakeCreds $ s ◁ stkCreds - s ⋪ (StakeKeys stKeys) = StakeKeys $ s ⋪ stKeys + s ⋪ (StakeCreds stkCreds) = StakeCreds $ s ⋪ stkCreds - (StakeKeys stKeys) ▷ s = StakeKeys $ stKeys ▷ s + (StakeCreds stkCreds) ▷ s = StakeCreds $ stkCreds ▷ s - (StakeKeys stKeys) ⋫ s = StakeKeys $ stKeys ⋫ s + (StakeCreds stkCreds) ⋫ s = StakeCreds $ stkCreds ⋫ s - (StakeKeys a) ∪ (StakeKeys b) = StakeKeys $ a ∪ b + (StakeCreds a) ∪ (StakeCreds b) = StakeCreds $ a ∪ b - (StakeKeys a) ⨃ b = StakeKeys $ a ⨃ b + (StakeCreds a) ⨃ b = StakeCreds $ a ⨃ b - vmax <=◁ (StakeKeys stKeys) = StakeKeys $ vmax <=◁ stKeys + vmax <=◁ (StakeCreds stkCreds) = StakeCreds $ vmax <=◁ stkCreds - (StakeKeys stKeys) ▷<= vmax = StakeKeys $ stKeys ▷<= vmax + (StakeCreds stkCreds) ▷<= vmax = StakeCreds $ stkCreds ▷<= vmax - (StakeKeys stKeys) ▷>= vmin = StakeKeys $ stKeys ▷>= vmin + (StakeCreds stkCreds) ▷>= vmin = StakeCreds $ stkCreds ▷>= vmin - size (StakeKeys stKeys) = size stKeys + size (StakeCreds stkCreds) = size stkCreds -- Lenses diff --git a/shelley/chain-and-ledger/executable-spec/src/UTxO.hs b/shelley/chain-and-ledger/executable-spec/src/UTxO.hs index 5ed36203d73..eea792f5b5c 100644 --- a/shelley/chain-and-ledger/executable-spec/src/UTxO.hs +++ b/shelley/chain-and-ledger/executable-spec/src/UTxO.hs @@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} @@ -37,6 +38,7 @@ module UTxO import Lens.Micro ((^.)) +import Cardano.Prelude (NoUnexpectedThunks(..)) import Data.Foldable (toList) import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map @@ -54,12 +56,12 @@ import TxData (Addr (..), Credential (..), ScriptHash, StakeCredential inputs, outputs, poolPubKey, txUpdate) import Updates (Update) -import Delegation.Certificates (DCert (..), StakePools (..), cwitness, dvalue) +import Delegation.Certificates (DCert (..), StakePools (..), cwitness, dvalue, isInstantaneousRewards) -- |The unspent transaction outputs. newtype UTxO hashAlgo dsignAlgo vrfAlgo = UTxO (Map (TxIn hashAlgo dsignAlgo vrfAlgo) (TxOut hashAlgo dsignAlgo)) - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, NoUnexpectedThunks) instance Relation (UTxO hashAlgo dsignAlgo vrfAlgo) where type Domain (UTxO hashAlgo dsignAlgo vrfAlgo) = TxIn hashAlgo dsignAlgo vrfAlgo @@ -219,7 +221,7 @@ scriptsNeeded u tx = `Set.union` Set.fromList (Maybe.mapMaybe (scriptStakeCred . getRwdCred) $ Map.keys withdrawals) `Set.union` - Set.fromList (Maybe.mapMaybe (scriptStakeCred . cwitness) certificates) + Set.fromList (Maybe.mapMaybe (scriptStakeCred . cwitness) (filter (not . isInstantaneousRewards) certificates)) where unTxOut (TxOut a _) = a withdrawals = _wdrls $ _body tx UTxO u'' = txinsScript (txins $ _body tx) u <| u diff --git a/shelley/chain-and-ledger/executable-spec/src/Updates.hs b/shelley/chain-and-ledger/executable-spec/src/Updates.hs index 9f3dfe68d44..251a41334a3 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Updates.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Updates.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} @@ -37,13 +38,15 @@ import qualified Data.Map.Strict as Map import Data.Set (Set) import qualified Data.Set as Set import Data.Word (Word8) +import GHC.Generics (Generic) import Cardano.Binary (ToCBOR (toCBOR), encodeListLen) import Cardano.Crypto.Hash (Hash, HashAlgorithm) +import Cardano.Prelude (NoUnexpectedThunks(..)) import BaseTypes (Nonce, UnitInterval) import Coin (Coin) -import Keys (DSIGNAlgorithm, Dms, GenKeyHash) +import Keys (DSIGNAlgorithm, GenDelegs, GenKeyHash) import PParams (PParams (..)) import Slot (Epoch, Slot) @@ -51,34 +54,35 @@ import Numeric.Natural (Natural) import Ledger.Core (dom, range, (∪), (◁)) - newtype ApVer = ApVer Natural - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, NoUnexpectedThunks, ToCBOR) newtype ApName = ApName ByteString - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, ToCBOR, NoUnexpectedThunks) newtype SystemTag = SystemTag ByteString - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, ToCBOR, NoUnexpectedThunks) newtype InstallerHash hashAlgo = InstallerHash (Hash hashAlgo ByteString) - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, ToCBOR, NoUnexpectedThunks) newtype Mdt hashAlgo = Mdt (Map SystemTag (InstallerHash hashAlgo)) - deriving (Show, Ord, Eq, ToCBOR) + deriving (Show, Ord, Eq, ToCBOR, NoUnexpectedThunks) newtype Applications hashAlgo = Applications { apps :: Map ApName (ApVer, Mdt hashAlgo) - } deriving (Show, Ord, Eq, ToCBOR) + } deriving (Show, Ord, Eq, ToCBOR, NoUnexpectedThunks) newtype AVUpdate hashAlgo dsignAlgo = AVUpdate { aup :: Map (GenKeyHash hashAlgo dsignAlgo) (Applications hashAlgo) - } deriving (Show, Eq, ToCBOR) + } deriving (Show, Eq, ToCBOR, NoUnexpectedThunks) -- | Update Proposal data Update hashAlgo dsignAlgo = Update (PPUpdate hashAlgo dsignAlgo) (AVUpdate hashAlgo dsignAlgo) - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (Update hashAlgo dsignAlgo) instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => ToCBOR (Update hashAlgo dsignAlgo) where toCBOR (Update ppUpdate avUpdate) = @@ -86,8 +90,10 @@ instance (HashAlgorithm hashAlgo, DSIGNAlgorithm dsignAlgo) => ToCBOR (Update ha data PPUpdateEnv hashAlgo dsignAlgo = PPUpdateEnv { slot :: Slot - , dms :: Dms hashAlgo dsignAlgo - } deriving (Show, Eq) + , genDelegs :: GenDelegs hashAlgo dsignAlgo + } deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (PPUpdateEnv hashAlgo dsignAlgo) data Ppm = MinFeeA Integer | MinFeeB Natural @@ -108,7 +114,9 @@ data Ppm = MinFeeA Integer | D UnitInterval | ExtraEntropy Nonce | ProtocolVersion (Natural, Natural, Natural) - deriving (Show, Ord, Eq) + deriving (Show, Ord, Eq, Generic) + +instance NoUnexpectedThunks Ppm instance ToCBOR Ppm where toCBOR = \case @@ -163,7 +171,7 @@ instance ToCBOR Ppm where newtype PPUpdate hashAlgo dsignAlgo = PPUpdate (Map (GenKeyHash hashAlgo dsignAlgo) (Set Ppm)) - deriving (Show, Eq, ToCBOR) + deriving (Show, Eq, ToCBOR, NoUnexpectedThunks) -- | Update Protocol Parameter update with new values, prefer value from `pup1` -- in case of already existing value in `pup0` @@ -261,4 +269,6 @@ data UpdateState hashAlgo dsignAlgo (AVUpdate hashAlgo dsignAlgo) (Map Slot (Applications hashAlgo)) (Applications hashAlgo) - deriving (Show, Eq) + deriving (Show, Eq, Generic) + +instance NoUnexpectedThunks (UpdateState hashAlgo dsignAlgo) diff --git a/shelley/chain-and-ledger/executable-spec/test/Cardano/Crypto/VRF/Fake.hs b/shelley/chain-and-ledger/executable-spec/test/Cardano/Crypto/VRF/Fake.hs index 871ca2cf546..fbefbc04f28 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Cardano/Crypto/VRF/Fake.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Cardano/Crypto/VRF/Fake.hs @@ -71,6 +71,7 @@ instance VRFAlgorithm FakeVRF where -- result of the sneaking. verifyVRF (VerKeyFakeVRF n) a c = snd (evalVRF' a (SignKeyFakeVRF n)) == snd c encodeVerKeyVRF = toCBOR + decodeVerKeyVRF = fromCBOR evalVRF' :: SneakilyContainResult a => a -> SignKeyVRF FakeVRF -> (Natural, CertVRF FakeVRF) evalVRF' a (SignKeyFakeVRF n) = diff --git a/shelley/chain-and-ledger/executable-spec/test/Examples.hs b/shelley/chain-and-ledger/executable-spec/test/Examples.hs index dd3097e0772..fe45ff3d631 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Examples.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Examples.hs @@ -28,6 +28,11 @@ module Examples , ex4C , ex5A , ex5B + , ex6A + , ex6B + , ex6C + , ex6D + , ex6E , maxLovelaceSupply -- key pairs and example addresses , alicePay @@ -50,6 +55,12 @@ module Examples where import Cardano.Binary (ToCBOR) +import Cardano.Crypto.DSIGN (deriveVerKeyDSIGN, genKeyDSIGN) +import Cardano.Crypto.Hash (ShortHash) +import Cardano.Crypto.KES (deriveVerKeyKES, genKeyKES) +import Cardano.Crypto.VRF (deriveVerKeyVRF, evalCertified, genKeyVRF) +import Cardano.Crypto.VRF.Fake (WithResult (..)) +import Crypto.Random (drgNewTest, withDRG) import Data.ByteString.Char8 (pack) import Data.Coerce (coerce) import Data.Map.Strict (Map) @@ -60,45 +71,48 @@ import Data.Sequence (empty, fromList) import Data.Set (Set) import qualified Data.Set as Set import Data.Word (Word64) -import Cardano.Crypto.DSIGN (deriveVerKeyDSIGN, genKeyDSIGN) -import Cardano.Crypto.Hash (ShortHash) -import Cardano.Crypto.KES (deriveVerKeyKES, genKeyKES) -import Cardano.Crypto.VRF (genKeyVRF, deriveVerKeyVRF, evalCertified) -import Cardano.Crypto.VRF.Fake (WithResult(..)) -import Crypto.Random (drgNewTest, withDRG) -import MockTypes (AVUpdate, Addr, Applications, Block, CertifiedVRF, ChainState, Credential, DState, - EpochState, GenKeyHash, HashHeader, KeyHash, KeyPair, LedgerState, Mdt, - PPUpdate, PState, PoolDistr, PoolParams, RewardAcnt, SKey, SKeyES, SnapShots, - Stake, Tx, TxBody, UTxO, UTxOState, Update, UpdateState, VKey, VKeyES, - VKeyGenesis, SignKeyVRF, VerKeyVRF) +import MockTypes (AVUpdate, Addr, Applications, Block, CHAIN, CertifiedVRF, ChainState, + Credential, DState, EpochState, GenKeyHash, HashHeader, KeyHash, KeyPair, + LedgerState, Mdt, NewEpochState, PPUpdate, PState, PoolDistr, PoolParams, + RewardAcnt, SKey, SKeyES, SignKeyVRF, SnapShots, Stake, Tx, TxBody, UTxO, + UTxOState, Update, UpdateState, VKey, VKeyES, VKeyGenesis, VerKeyVRF) import Numeric.Natural (Natural) import Unsafe.Coerce (unsafeCoerce) -import BaseTypes (Nonce (..), UnitInterval, intervalValue, mkUnitInterval, mkNonce, (⭒)) +import BaseTypes (Nonce (..), UnitInterval, intervalValue, mkNonce, mkUnitInterval, (⭒)) import BlockChain (pattern BHBody, pattern BHeader, pattern Block, pattern HashHeader, - ProtVer (..), TxSeq (..), bBodySize, bhHash, bhbHash, bheader, - seedL, seedEta, mkSeed) + ProtVer (..), TxSeq (..), bBodySize, bhHash, bhbHash, bheader, mkSeed, + seedEta, seedL) import Coin (Coin (..)) import Delegation.Certificates (pattern DeRegKey, pattern Delegate, - pattern GenesisDelegate, pattern PoolDistr, pattern RegKey, pattern RegPool, - pattern RetirePool) + pattern GenesisDelegate, pattern InstantaneousRewards, pattern PoolDistr, + pattern RegKey, pattern RegPool, pattern RetirePool) import EpochBoundary (BlocksMade (..), pattern SnapShots, pattern Stake, emptySnapShots, _feeSS, _poolsSS, _pstakeGo, _pstakeMark, _pstakeSet) -import Keys (pattern Dms, Hash, pattern KeyPair, pattern SKey, pattern SKeyES, - pattern VKey, pattern VKeyES, pattern VKeyGenesis, hash, hashKey, hashKeyVRF - , sKey, sign, signKES, vKey) +import Keys (pattern GenDelegs, Hash, pattern KeyPair, pattern SKey, pattern SKeyES, + pattern VKey, pattern VKeyES, pattern VKeyGenesis, hash, hashKey, hashKeyVRF, + sKey, sign, signKES, vKey) import LedgerState (AccountState (..), pattern DPState, pattern EpochState, pattern LedgerState, pattern NewEpochState, pattern RewardUpdate, - pattern UTxOState, deltaF, deltaR, deltaT, emptyDState, emptyPState, - genesisCoins, genesisId, overlaySchedule, rs, _cCounters, _delegations, _dms, - _fdms, _pParams, _ptrs, _reserves, _retiring, _rewards, _stKeys, _stPools, - _treasury) + pattern UTxOState, deltaDeposits, deltaF, deltaR, deltaT, emptyDState, + emptyPState, esAccountState, esPp, genesisCoins, genesisId, nesEs, + overlaySchedule, rs, updateIRwd, _cCounters, _delegations, _fGenDelegs, + _genDelegs, _irwd, _pParams, _ptrs, _reserves, _retiring, _rewards, _stPools, + _stkCreds, _treasury) import OCert (KESPeriod (..), pattern OCert) import PParams (PParams (..), emptyPParams) import Slot (Epoch (..), Slot (..)) -import STS.Chain (pattern ChainState) +import STS.Bbody (pattern LedgersFailure) +import STS.Chain (pattern BbodyFailure, pattern ChainState, chainNes) +import STS.Deleg (pattern InsufficientForInstantaneousRewardsDELEG) +import STS.Delegs (pattern DelplFailure) +import STS.Delpl (pattern DelegFailure) +import STS.Ledger (pattern DelegsFailure, pattern UtxowFailure) +import STS.Ledgers (pattern LedgerFailure) +import STS.Utxow (pattern MIRImpossibleInDecentralizedNetUTXOW, + pattern MIRInsufficientGenesisSigsUTXOW) import TxData (pattern AddrBase, pattern AddrPtr, pattern Delegation, pattern KeyHashObj, - pattern PoolParams, Ptr (..), pattern RewardAcnt, pattern StakeKeys, + pattern PoolParams, Ptr (..), pattern RewardAcnt, pattern StakeCreds, pattern StakePools, pattern Tx, pattern TxBody, pattern TxIn, pattern TxOut, _paymentObj, _poolCost, _poolMargin, _poolOwners, _poolPledge, _poolPubKey, _poolRAcnt, _poolVrf) @@ -108,8 +122,10 @@ import Updates (pattern AVUpdate, ApName (..), ApVer (..), pattern App updatePPup) import UTxO (pattern UTxO, balance, makeGenWitnessesVKey, makeWitnessesVKey, txid) +import Control.State.Transition (PredicateFailure) -data CHAINExample = CHAINExample Slot ChainState Block ChainState +data CHAINExample = + CHAINExample Slot ChainState Block (Either [[PredicateFailure CHAIN]] ChainState) -- | Set up keys for all the actors in the examples. @@ -179,8 +195,8 @@ coreNodeVKG = snd . fst . (coreNodes !!) coreNodeKeys :: Int -> AllPoolKeys coreNodeKeys = snd . (coreNodes !!) -dms :: Map GenKeyHash KeyHash -dms = Map.fromList [ (hashKey $ snd gkey, hashKey . vKey $ cold pkeys) | (gkey, pkeys) <- coreNodes] +genDelegs :: Map GenKeyHash KeyHash +genDelegs = Map.fromList [ (hashKey $ snd gkey, hashKey . vKey $ cold pkeys) | (gkey, pkeys) <- coreNodes] byronApps :: Applications byronApps = Applications $ Map.fromList @@ -326,10 +342,10 @@ utxostEx1 :: UTxOState utxostEx1 = UTxOState (UTxO Map.empty) (Coin 0) (Coin 0) emptyUpdateState dsEx1 :: DState -dsEx1 = emptyDState { _dms = Dms dms } +dsEx1 = emptyDState { _genDelegs = GenDelegs genDelegs } psEx1 :: PState -psEx1 = emptyPState { _cCounters = Map.fromList (fmap f (Map.elems dms)) } +psEx1 = emptyPState { _cCounters = Map.fromList (fmap f (Map.elems genDelegs)) } where f vk = (vk, 0) lsEx1 :: LedgerState @@ -430,7 +446,7 @@ expectedStEx1 = ChainState (Slot 1) ex1 :: CHAINExample -ex1 = CHAINExample (Slot 1) initStEx1 blockEx1 expectedStEx1 +ex1 = CHAINExample (Slot 1) initStEx1 blockEx1 (Right expectedStEx1) -- | Example 2A - apply CHAIN transition to register stake keys and a pool @@ -495,21 +511,25 @@ esEx2A = EpochState acntEx2A emptySnapShots lsEx2A ppsEx1 overlayEx2A :: Map Slot (Maybe GenKeyHash) overlayEx2A = overlaySchedule (Epoch 0) - (Map.keysSet dms) + (Map.keysSet genDelegs) NeutralNonce ppsEx1 +initNesEx2A :: NewEpochState +initNesEx2A = NewEpochState + (Epoch 0) + (mkNonce 0) + (BlocksMade Map.empty) + (BlocksMade Map.empty) + esEx2A + Nothing + (PoolDistr Map.empty) + overlayEx2A + + initStEx2A :: ChainState initStEx2A = ChainState - (NewEpochState - (Epoch 0) - (mkNonce 0) - (BlocksMade Map.empty) - (BlocksMade Map.empty) - esEx2A - Nothing - (PoolDistr Map.empty) - overlayEx2A) + initNesEx2A (mkNonce 0) (mkNonce 0) lastByronHeaderHash @@ -530,7 +550,7 @@ dsEx2A :: DState dsEx2A = dsEx1 { _ptrs = Map.fromList [ (Ptr (Slot 10) 0 0, aliceSHK) , (Ptr (Slot 10) 0 1, bobSHK) ] - , _stKeys = StakeKeys $ Map.fromList [ (aliceSHK, Slot 10) + , _stkCreds = StakeCreds $ Map.fromList [ (aliceSHK, Slot 10) , (bobSHK, Slot 10) ] , _rewards = Map.fromList [ (RewardAcnt aliceSHK, Coin 0) , (RewardAcnt bobSHK, Coin 0) ] @@ -583,7 +603,7 @@ expectedStEx2A = ChainState (Slot 10) ex2A :: CHAINExample -ex2A = CHAINExample (Slot 10) initStEx2A blockEx2A expectedStEx2A +ex2A = CHAINExample (Slot 10) initStEx2A blockEx2A (Right expectedStEx2A) -- | Example 2B - process a block late enough in the epoch in order to create a reward update. @@ -657,10 +677,12 @@ expectedStEx2Bgeneric pp = ChainState (BlocksMade Map.empty) (BlocksMade Map.empty) (EpochState acntEx2A emptySnapShots expectedLSEx2B pp) - (Just RewardUpdate { deltaT = Coin 0 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin 0 + (Just RewardUpdate { deltaT = Coin 0 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin 0 + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) (PoolDistr Map.empty) overlayEx2A) @@ -682,7 +704,7 @@ expectedStEx2Bquater :: ChainState expectedStEx2Bquater = expectedStEx2Bgeneric ppsExInstantDecay ex2B :: CHAINExample -ex2B = CHAINExample (Slot 90) expectedStEx2A blockEx2B expectedStEx2B +ex2B = CHAINExample (Slot 90) expectedStEx2A blockEx2B (Right expectedStEx2B) -- | Example 2C - process an empty block in the next epoch -- so that the (empty) reward update is applied and a stake snapshot is made. @@ -702,7 +724,7 @@ blockEx2C = mkBlock epoch1OSchedEx2C :: Map Slot (Maybe GenKeyHash) epoch1OSchedEx2C = overlaySchedule (Epoch 1) - (Map.keysSet dms) + (Map.keysSet genDelegs) (mkNonce 0 ⭒ mkNonce 1) ppsEx1 @@ -785,17 +807,17 @@ expectedStEx2Cquater = expectedStEx2Cgeneric snapsEx2Cquater expectedLSEx2Cquater ppsExInstantDecay ex2C :: CHAINExample -ex2C = CHAINExample (Slot 110) expectedStEx2B blockEx2C expectedStEx2C +ex2C = CHAINExample (Slot 110) expectedStEx2B blockEx2C (Right expectedStEx2C) ex2Cbis :: CHAINExample -ex2Cbis = CHAINExample (Slot 110) expectedStEx2Bbis blockEx2C expectedStEx2Cbis +ex2Cbis = CHAINExample (Slot 110) expectedStEx2Bbis blockEx2C (Right expectedStEx2Cbis) ex2Cter :: CHAINExample -ex2Cter = CHAINExample (Slot 110) expectedStEx2Bter blockEx2C expectedStEx2Cter +ex2Cter = CHAINExample (Slot 110) expectedStEx2Bter blockEx2C (Right expectedStEx2Cter) ex2Cquater :: CHAINExample ex2Cquater = - CHAINExample (Slot 110) expectedStEx2Bquater blockEx2C expectedStEx2Cquater + CHAINExample (Slot 110) expectedStEx2Bquater blockEx2C (Right expectedStEx2Cquater) -- | Example 2D - process an empty block late enough @@ -825,10 +847,12 @@ expectedStEx2D = ChainState (BlocksMade Map.empty) (BlocksMade Map.empty) (EpochState acntEx2A snapsEx2C expectedLSEx2C ppsEx1) - (Just RewardUpdate { deltaT = Coin 20 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin (-20) + (Just RewardUpdate { deltaT = Coin 20 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin (-20) + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) (PoolDistr Map.empty) epoch1OSchedEx2C) @@ -838,7 +862,7 @@ expectedStEx2D = ChainState (Slot 190) ex2D :: CHAINExample -ex2D = CHAINExample (Slot 190) expectedStEx2C blockEx2D expectedStEx2D +ex2D = CHAINExample (Slot 190) expectedStEx2C blockEx2D (Right expectedStEx2D) -- | Example 2E - create the first non-empty pool distribution @@ -859,7 +883,7 @@ blockEx2E = mkBlock epoch1OSchedEx2E :: Map Slot (Maybe GenKeyHash) epoch1OSchedEx2E = overlaySchedule (Epoch 2) - (Map.keysSet dms) + (Map.keysSet genDelegs) (mkSeqNonce 3) ppsEx1 @@ -909,7 +933,7 @@ expectedStEx2E = ChainState (Slot 220) ex2E :: CHAINExample -ex2E = CHAINExample (Slot 220) expectedStEx2D blockEx2E expectedStEx2E +ex2E = CHAINExample (Slot 220) expectedStEx2D blockEx2E (Right expectedStEx2E) -- | Example 2F - create a decentralized Praos block (ie one not in the overlay schedule) @@ -940,10 +964,12 @@ expectedStEx2F = ChainState (BlocksMade Map.empty) (BlocksMade $ Map.singleton (hk alicePool) 1) (EpochState acntEx2E snapsEx2E expectedLSEx2E ppsEx1) - (Just RewardUpdate { deltaT = Coin 13 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin (-13) + (Just RewardUpdate { deltaT = Coin 13 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin (-13) + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) pdEx2F epoch1OSchedEx2E) @@ -953,7 +979,7 @@ expectedStEx2F = ChainState (Slot 295) ex2F :: CHAINExample -ex2F = CHAINExample (Slot 295) expectedStEx2E blockEx2F expectedStEx2F +ex2F = CHAINExample (Slot 295) expectedStEx2E blockEx2F (Right expectedStEx2F) -- | Example 2G - create an empty block in the next epoch @@ -977,7 +1003,7 @@ blockEx2GHash = bhHash (bheader blockEx2G) epoch1OSchedEx2G :: Map Slot (Maybe GenKeyHash) epoch1OSchedEx2G = overlaySchedule (Epoch 3) - (Map.keysSet dms) + (Map.keysSet genDelegs) (mkSeqNonce 5) ppsEx1 @@ -1012,7 +1038,7 @@ expectedStEx2G = ChainState (Slot 310) ex2G :: CHAINExample -ex2G = CHAINExample (Slot 310) expectedStEx2F blockEx2G expectedStEx2G +ex2G = CHAINExample (Slot 310) expectedStEx2F blockEx2G (Right expectedStEx2G) -- | Example 2H - create the first non-trivial reward update @@ -1050,10 +1076,12 @@ expectedStEx2H = ChainState (BlocksMade $ Map.singleton (hk alicePool) 1) (BlocksMade Map.empty) (EpochState (acntEx2E { _treasury = Coin 33 }) snapsEx2G expectedLSEx2G ppsEx1) - (Just RewardUpdate { deltaT = Coin 9374400000008 - , deltaR = Coin (-9449999999997) - , rs = rewardsEx2H - , deltaF = Coin (-10) + (Just RewardUpdate { deltaT = Coin 9374400000008 + , deltaR = Coin (-9449999999997) + , rs = rewardsEx2H + , deltaF = Coin (-10) + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) pdEx2F epoch1OSchedEx2G) @@ -1063,7 +1091,7 @@ expectedStEx2H = ChainState (Slot 390) ex2H :: CHAINExample -ex2H = CHAINExample (Slot 390) expectedStEx2G blockEx2H expectedStEx2H +ex2H = CHAINExample (Slot 390) expectedStEx2G blockEx2H (Right expectedStEx2H) -- | Example 2I - apply the first non-trivial reward update @@ -1086,7 +1114,7 @@ blockEx2IHash = bhHash (bheader blockEx2I) epoch1OSchedEx2I :: Map Slot (Maybe GenKeyHash) epoch1OSchedEx2I = overlaySchedule (Epoch 4) - (Map.keysSet dms) + (Map.keysSet genDelegs) (mkSeqNonce 7) ppsEx1 @@ -1135,7 +1163,7 @@ expectedStEx2I = ChainState (Slot 410) ex2I :: CHAINExample -ex2I = CHAINExample (Slot 410) expectedStEx2H blockEx2I expectedStEx2I +ex2I = CHAINExample (Slot 410) expectedStEx2H blockEx2I (Right expectedStEx2I) -- | Example 2J - drain reward account and de-register stake key @@ -1186,7 +1214,7 @@ utxoEx2J = UTxO . Map.fromList $ dsEx2J :: DState dsEx2J = dsEx1 { _ptrs = Map.fromList [ (Ptr (Slot 10) 0 0, aliceSHK) ] - , _stKeys = StakeKeys $ Map.singleton aliceSHK (Slot 10) + , _stkCreds = StakeCreds $ Map.singleton aliceSHK (Slot 10) , _delegations = Map.singleton aliceSHK (hk alicePool) , _rewards = Map.singleton (RewardAcnt aliceSHK) aliceRAcnt2H } @@ -1218,7 +1246,7 @@ expectedStEx2J = ChainState (Slot 420) ex2J :: CHAINExample -ex2J = CHAINExample (Slot 420) expectedStEx2I blockEx2J expectedStEx2J +ex2J = CHAINExample (Slot 420) expectedStEx2I blockEx2J (Right expectedStEx2J) -- | Example 2K - start stake pool retirement @@ -1283,10 +1311,12 @@ expectedStEx2K = ChainState (BlocksMade Map.empty) (BlocksMade Map.empty) (EpochState acntEx2I snapsEx2I expectedLSEx2K ppsEx1) - (Just RewardUpdate { deltaT = Coin 9 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin (-9) + (Just RewardUpdate { deltaT = Coin 9 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin (-9) + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) pdEx2F epoch1OSchedEx2I) @@ -1296,7 +1326,7 @@ expectedStEx2K = ChainState (Slot 490) ex2K :: CHAINExample -ex2K = CHAINExample (Slot 490) expectedStEx2J blockEx2K expectedStEx2K +ex2K = CHAINExample (Slot 490) expectedStEx2J blockEx2K (Right expectedStEx2K) -- | Example 2L - reap a stake pool @@ -1332,7 +1362,7 @@ snapsEx2L = SnapShots { _pstakeMark = dsEx2L :: DState dsEx2L = dsEx1 { _ptrs = Map.singleton (Ptr (Slot 10) 0 0) aliceSHK - , _stKeys = StakeKeys $ Map.singleton aliceSHK (Slot 10) + , _stkCreds = StakeCreds $ Map.singleton aliceSHK (Slot 10) , _rewards = Map.singleton (RewardAcnt aliceSHK) (aliceRAcnt2H + Coin 201) -- Note the pool cert refund of 201 } @@ -1357,14 +1387,14 @@ expectedStEx2L = ChainState (EpochState acntEx2L snapsEx2L expectedLSEx2L ppsEx1) Nothing pdEx2F - (overlaySchedule (Epoch 5) (Map.keysSet dms) (mkSeqNonce 10) ppsEx1)) + (overlaySchedule (Epoch 5) (Map.keysSet genDelegs) (mkSeqNonce 10) ppsEx1)) (mkSeqNonce 12) (mkSeqNonce 12) blockEx2LHash (Slot 510) ex2L :: CHAINExample -ex2L = CHAINExample (Slot 510) expectedStEx2K blockEx2L expectedStEx2L +ex2L = CHAINExample (Slot 510) expectedStEx2K blockEx2L (Right expectedStEx2L) -- | Example 3A - Setting up for a successful protocol parameter update, @@ -1456,7 +1486,7 @@ expectedStEx3A = ChainState (Slot 10) ex3A :: CHAINExample -ex3A = CHAINExample (Slot 10) initStEx2A blockEx3A expectedStEx3A +ex3A = CHAINExample (Slot 10) initStEx2A blockEx3A (Right expectedStEx3A) -- | Example 3B - Finish getting enough votes for the protocol parameter update. @@ -1545,7 +1575,7 @@ expectedStEx3B = ChainState (Slot 20) ex3B :: CHAINExample -ex3B = CHAINExample (Slot 20) expectedStEx3A blockEx3B expectedStEx3B +ex3B = CHAINExample (Slot 20) expectedStEx3A blockEx3B (Right expectedStEx3B) -- | Example 3C - Adopt protocol parameter update @@ -1568,7 +1598,7 @@ blockEx3CHash = bhHash (bheader blockEx3C) overlayEx3C :: Map Slot (Maybe GenKeyHash) overlayEx3C = overlaySchedule (Epoch 1) - (Map.keysSet dms) + (Map.keysSet genDelegs) (mkSeqNonce 2) ppsEx1 @@ -1606,7 +1636,7 @@ expectedStEx3C = ChainState (Slot 110) ex3C :: CHAINExample -ex3C = CHAINExample (Slot 110) expectedStEx3B blockEx3C expectedStEx3C +ex3C = CHAINExample (Slot 110) expectedStEx3B blockEx3C (Right expectedStEx3C) -- | Example 4A - Setting up for a successful application version update, @@ -1705,7 +1735,7 @@ expectedStEx4A = ChainState (Slot 10) ex4A :: CHAINExample -ex4A = CHAINExample (Slot 10) initStEx2A blockEx4A expectedStEx4A +ex4A = CHAINExample (Slot 10) initStEx2A blockEx4A (Right expectedStEx4A) -- | Example 4B - Finish getting enough votes for the application version update. @@ -1793,7 +1823,7 @@ expectedStEx4B = ChainState (Slot 20) ex4B :: CHAINExample -ex4B = CHAINExample (Slot 20) expectedStEx4A blockEx4B expectedStEx4B +ex4B = CHAINExample (Slot 20) expectedStEx4A blockEx4B (Right expectedStEx4B) -- | Example 4C - Adopt application version update @@ -1841,11 +1871,13 @@ expectedStEx4C = ChainState (BlocksMade Map.empty) (BlocksMade Map.empty) (EpochState acntEx2A emptySnapShots expectedLSEx4C ppsEx1) - (Just RewardUpdate { deltaT = Coin 0 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin 0 - }) + (Just RewardUpdate { deltaT = Coin 0 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin 0 + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty + }) (PoolDistr Map.empty) overlayEx2A) (mkSeqNonce 3) @@ -1855,7 +1887,7 @@ expectedStEx4C = ChainState ex4C :: CHAINExample -ex4C = CHAINExample (Slot 60) expectedStEx4B blockEx4C expectedStEx4C +ex4C = CHAINExample (Slot 60) expectedStEx4B blockEx4C (Right expectedStEx4C) -- | Example 5A - Genesis key delegation @@ -1898,7 +1930,7 @@ blockEx5AHash :: HashHeader blockEx5AHash = bhHash (bheader blockEx5A) dsEx5A :: DState -dsEx5A = dsEx1 { _fdms = Map.singleton +dsEx5A = dsEx1 { _fGenDelegs = Map.singleton ( Slot 43, hashKey $ coreNodeVKG 0 ) ( (hashKey . vKey) newGenDelegate ) } @@ -1935,7 +1967,7 @@ expectedStEx5A = ChainState (Slot 10) ex5A :: CHAINExample -ex5A = CHAINExample (Slot 10) initStEx2A blockEx5A expectedStEx5A +ex5A = CHAINExample (Slot 10) initStEx2A blockEx5A (Right expectedStEx5A) -- | Example 5B - New genesis key delegation updated from future delegations @@ -1955,11 +1987,11 @@ blockEx5BHash :: HashHeader blockEx5BHash = bhHash (bheader blockEx5B) dsEx5B :: DState -dsEx5B = dsEx5A { _fdms = Map.empty - , _dms = Dms $ Map.insert +dsEx5B = dsEx5A { _fGenDelegs = Map.empty + , _genDelegs = GenDelegs $ Map.insert ((hashKey . coreNodeVKG) 0) ((hashKey . vKey) newGenDelegate) - dms } + genDelegs } psEx5B :: PState psEx5B = psEx1 { _cCounters = @@ -1987,10 +2019,12 @@ expectedStEx5B = ChainState (BlocksMade Map.empty) (BlocksMade Map.empty) (EpochState acntEx2A emptySnapShots expectedLSEx5B ppsEx1) - (Just RewardUpdate { deltaT = Coin 0 - , deltaR = Coin 0 - , rs = Map.empty - , deltaF = Coin 0 + (Just RewardUpdate { deltaT = Coin 0 + , deltaR = Coin 0 + , rs = Map.empty + , deltaF = Coin 0 + , deltaDeposits = Coin 0 + , updateIRwd = Map.empty }) (PoolDistr Map.empty) overlayEx2A) @@ -2000,4 +2034,156 @@ expectedStEx5B = ChainState (Slot 50) ex5B :: CHAINExample -ex5B = CHAINExample (Slot 50) expectedStEx5A blockEx5B expectedStEx5B +ex5B = CHAINExample (Slot 50) expectedStEx5A blockEx5B (Right expectedStEx5B) + + +-- | Example 6A - Genesis key delegation + + +ir :: Map Credential Coin +ir = Map.fromList [(aliceSHK, Coin 100)] + +txbodyEx6A :: TxBody +txbodyEx6A = TxBody + (Set.fromList [TxIn genesisId 0]) + [TxOut aliceAddr (Coin 9999)] + (fromList [InstantaneousRewards ir]) + Map.empty + (Coin 1) + (Slot 10) + emptyUpdate + +txEx6A :: Tx +txEx6A = Tx + txbodyEx6A + (makeWitnessesVKey txbodyEx6A [ alicePay ] `Set.union` makeGenWitnessesVKey txbodyEx6A + [ KeyPair (coreNodeVKG 0) (coreNodeSKG 0) + , KeyPair (coreNodeVKG 1) (coreNodeSKG 1) + , KeyPair (coreNodeVKG 2) (coreNodeSKG 2) + , KeyPair (coreNodeVKG 3) (coreNodeSKG 3) + , KeyPair (coreNodeVKG 4) (coreNodeSKG 4) + ]) + Map.empty + +blockEx6A :: Block +blockEx6A = mkBlock + lastByronHeaderHash + (coreNodeKeys 6) + [txEx6A] + (Slot 10) + (mkNonce 0) + (NatNonce 1) + zero + 0 + +blockEx6AHash :: HashHeader +blockEx6AHash = bhHash (bheader blockEx6A) + +utxoEx6A :: UTxO +utxoEx6A = UTxO . Map.fromList $ + [ (TxIn genesisId 1, TxOut bobAddr bobInitCoin) + , (TxIn (txid txbodyEx6A) 0, TxOut aliceAddr (Coin 9999)) + ] + +dsEx6A :: DState +dsEx6A = dsEx1 { _irwd = Map.fromList [(aliceSHK, Coin 100)] } + +expectedLSEx6A :: LedgerState +expectedLSEx6A = LedgerState + (UTxOState + utxoEx6A + (Coin 0) + (Coin 1) + (UpdateState (PPUpdate Map.empty) (AVUpdate Map.empty) Map.empty byronApps)) + (DPState dsEx6A psEx1) + 0 + +expectedStEx6A :: ChainState +expectedStEx6A = ChainState + (NewEpochState + (Epoch 0) + (mkNonce 0) + (BlocksMade Map.empty) + (BlocksMade Map.empty) + (EpochState acntEx2A emptySnapShots expectedLSEx6A ppsEx1) + Nothing + (PoolDistr Map.empty) + overlayEx2A) + (mkNonce 0 ⭒ mkNonce 1) + (mkNonce 0 ⭒ mkNonce 1) + blockEx6AHash + (Slot 10) + +ex6A :: CHAINExample +ex6A = CHAINExample (Slot 10) initStEx2A blockEx6A (Right expectedStEx6A) + + +-- | Example 6B - Instantaneous rewards with insufficient core node signatures + +txEx6B :: Tx +txEx6B = Tx + txbodyEx6A + (makeWitnessesVKey txbodyEx6A [ alicePay ] `Set.union` makeGenWitnessesVKey txbodyEx6A + [ KeyPair (coreNodeVKG 0) (coreNodeSKG 0) + , KeyPair (coreNodeVKG 1) (coreNodeSKG 1) + , KeyPair (coreNodeVKG 2) (coreNodeSKG 2) + , KeyPair (coreNodeVKG 3) (coreNodeSKG 3) + ]) + Map.empty + +blockEx6B :: Block +blockEx6B = mkBlock + lastByronHeaderHash + (coreNodeKeys 6) + [txEx6B] + (Slot 10) + (mkNonce 0) + (NatNonce 1) + zero + 0 + +expectedStEx6B :: PredicateFailure CHAIN +expectedStEx6B = BbodyFailure (LedgersFailure (LedgerFailure (UtxowFailure MIRInsufficientGenesisSigsUTXOW))) + +ex6B :: CHAINExample +ex6B = CHAINExample (Slot 10) initStEx2A blockEx6B (Left [[expectedStEx6B]]) + +-- | Example 6C - Instantaneous rewards in decentralized era + +expectedStEx6C :: PredicateFailure CHAIN +expectedStEx6C = BbodyFailure (LedgersFailure (LedgerFailure (UtxowFailure MIRImpossibleInDecentralizedNetUTXOW))) + +ex6C :: CHAINExample +ex6C = + CHAINExample + (Slot 10) + (initStEx2A { chainNes = initNesEx2A { nesEs = esEx2A { esPp = ppsEx1 { _d = unsafeMkUnitInterval 0 }}}}) + blockEx6A + (Left [[expectedStEx6C]]) + + +-- | Example 6D - Instantaneous rewards in decentralized era and not enough core +-- signatures + +ex6D :: CHAINExample +ex6D = + CHAINExample + (Slot 10) + (initStEx2A { chainNes = initNesEx2A { nesEs = esEx2A { esPp = ppsEx1 { _d = unsafeMkUnitInterval 0 }}}}) + blockEx6B + (Left [[expectedStEx6C, expectedStEx6B]]) + +-- | Example 6E - Instantaneous rewards that overrun the available reserves + +ex6E :: CHAINExample +ex6E = + CHAINExample + (Slot 10) + (initStEx2A { chainNes = initNesEx2A { nesEs = esEx2A { esAccountState = acntEx2A { _reserves = 99 }}}}) + blockEx6A + (Left [[BbodyFailure + (LedgersFailure + (LedgerFailure + (DelegsFailure + (DelplFailure + (DelegFailure InsufficientForInstantaneousRewardsDELEG)))))]]) diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator.hs b/shelley/chain-and-ledger/executable-spec/test/Generator.hs index 214f66be6d3..8e40d9a8da3 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Generator.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Generator.hs @@ -5,25 +5,20 @@ module Generator ( utxoSize , utxoMap - , genBool - , genNatural , genNonEmptyAndAdvanceTx , genNonEmptyAndAdvanceTx' , genNonemptyGenesisState - , genStakePool , genStateTx , genValidStateTx , genValidStateTxKeys , genDelegationData , genDelegation - , genDCertRegPool , genDCertDelegate , genKeyPairs ) where import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map -import Data.Ratio import Data.Sequence (Seq (..)) import qualified Data.Set as Set @@ -35,19 +30,17 @@ import Hedgehog import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import BaseTypes import Coin -import Generator.Core (findPayKeyPair) -import Keys (pattern KeyPair, hashKey, hashKeyVRF, vKey) +import Generator.Core (findPayKeyPair, genNatural) +import Keys (pattern KeyPair, hashKey, vKey) import LedgerState (DState (..), pattern LedgerValidation, ValidationError (..), asStateTransition, asStateTransition', dstate, genesisCoins, genesisState, - stKeys, utxo, utxoState, _delegationState, _dstate) + stkCreds, utxo, utxoState, _delegationState, _dstate) import PParams (PParams (..), emptyPParams) import Slot import Tx (pattern Tx, pattern TxBody, pattern TxOut) import TxData (pattern AddrBase, pattern DeRegKey, pattern Delegate, pattern Delegation, - pattern KeyHashObj, pattern PoolParams, pattern RegKey, pattern RegPool, - pattern RetirePool, RewardAcnt (..), StakeKeys (..)) + pattern KeyHashObj, pattern RegKey, pattern RetirePool, StakeCreds (..)) import Updates import UTxO (pattern UTxO, balance, makeWitnessVKey) @@ -87,16 +80,6 @@ hashKeyPairs keyPairs = addrTxins :: KeyPairs -> [Addr] addrTxins keyPairs = uncurry AddrBase <$> hashKeyPairs keyPairs -genBool :: Gen Bool -genBool = Gen.enumBounded - --- | Generator for a natural number between 'lower' and 'upper'. -genNatural :: Natural -> Natural -> Gen Natural -genNatural lower upper = Gen.integral $ Range.linear lower upper - -genInteger :: Integer -> Integer -> Gen Integer -genInteger lower upper = Gen.integral $ Range.linear lower upper - -- | Generator for List of 'Coin' values. Generates between 'lower' and 'upper' -- coins, with values between 'minCoin' and 'maxCoin'. genCoinList :: Integer -> Integer -> Int -> Int -> Gen [Coin] @@ -167,10 +150,10 @@ genLedgerStateTx :: KeyPairs -> Slot -> LedgerState -> Gen (Coin, Tx, Either [ValidationError] LedgerState) genLedgerStateTx keyList (Slot _slot) sourceState = do let utxo' = sourceState ^. utxoState . utxo - let dms' = _dms $ _dstate $ _delegationState sourceState + let genDelegs' = _genDelegs $ _dstate $ _delegationState sourceState slot' <- genNatural _slot (_slot + 100) (txfee', tx) <- genTx keyList utxo' (Slot slot') - pure (txfee', tx, asStateTransition (Slot slot') defPCs sourceState tx dms') + pure (txfee', tx, asStateTransition (Slot slot') defPCs sourceState tx genDelegs') -- | Generator of a non-emtpy ledger genesis state and a random number of -- transactions applied to it. Returns the amount of accumulated fees, the @@ -279,13 +262,13 @@ genLedgerStateTx' :: KeyPairs -> LedgerState -> Gen (Coin, Tx, LedgerValidation) genLedgerStateTx' keyList sourceState = do let utxo' = sourceState ^. utxoState . utxo - let dms' = _dms $ _dstate $ _delegationState sourceState + let genDelegs' = _genDelegs $ _dstate $ _delegationState sourceState _slot <- genNatural 0 1000 (txfee', tx) <- genTx keyList utxo' (Slot _slot) tx' <- mutateTx tx pure (txfee' , tx' - , asStateTransition' (Slot _slot) defPCs (LedgerValidation [] sourceState) tx' dms') + , asStateTransition' (Slot _slot) defPCs (LedgerValidation [] sourceState) tx' genDelegs') -- Generators for 'DelegationData' @@ -308,35 +291,12 @@ genDCertRetirePool keys epoch = do key <- getAnyStakeKey keys pure $ RetirePool (hashKey key) epoch -genStakePool :: KeyPairs -> [(SignKeyVRF, VerKeyVRF)] -> Gen PoolParams -genStakePool skeys vrfKeys = do - poolKey <- getAnyStakeKey skeys - vrfKey <- snd <$> Gen.element vrfKeys - cost <- Coin <$> genInteger 1 100 - pledge <- Coin <$> genInteger 1 100 - marginPercent <- genNatural 0 100 - acntKey <- getAnyStakeKey skeys - let interval = case mkUnitInterval $ fromIntegral marginPercent % 100 of - Just i -> i - Nothing -> interval0 - pure $ PoolParams - (hashKey poolKey) - (hashKeyVRF vrfKey) - pledge - cost - interval - (RewardAcnt $ KeyHashObj $ hashKey acntKey) - Set.empty - genDelegation :: KeyPairs -> DPState -> Gen Delegation genDelegation keys d = do - poolKey <- Gen.element $ Map.keys stKeys' + poolKey <- Gen.element $ Map.keys stkCreds' delegatorKey <- getAnyStakeKey keys pure $ Delegation (KeyHashObj $ hashKey delegatorKey) $ (hashKey $ vKey $ findStakeKeyPair poolKey keys) - where (StakeKeys stKeys') = d ^. dstate . stKeys - -genDCertRegPool :: KeyPairs -> [(SignKeyVRF, VerKeyVRF)] -> Gen DCert -genDCertRegPool skeys vrfKeys = RegPool <$> genStakePool skeys vrfKeys + where (StakeCreds stkCreds') = d ^. dstate . stkCreds genDCertDelegate :: KeyPairs -> DPState -> Gen DCert genDCertDelegate keys ds = Delegate <$> genDelegation keys ds diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator/Core.hs b/shelley/chain-and-ledger/executable-spec/test/Generator/Core.hs index fb793521e63..c72eb2bb5be 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Generator/Core.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Generator/Core.hs @@ -4,16 +4,24 @@ module Generator.Core ( findPayKeyPair + , genBool + , genCoin + , genInteger + , genNatural , genTxOut , genUtxo0 + , increasingProbabilityAt , mkGenesisLedgerState , traceKeyPairs + , traceVRFKeyPairs , someKeyPairs , pickStakeKey , toAddr , toCred) where +import Cardano.Crypto.VRF (deriveVerKeyVRF, genKeyVRF) +import Crypto.Random (drgNewTest, withDRG) import Data.Tuple (swap) import Data.Word (Word64) import Hedgehog (Gen) @@ -25,11 +33,22 @@ import Coin (Coin (..)) import Examples (mkKeyPair) import Keys (pattern KeyPair, hashKey, vKey) import LedgerState (pattern LedgerState, genesisCoins, genesisState) -import MockTypes (Addr, DPState, KeyPair, KeyPairs, LedgerEnv, TxOut, UTxO, UTxOState, - VKey) +import MockTypes (Addr, DPState, KeyPair, KeyPairs, LedgerEnv, SignKeyVRF, TxOut, UTxO, + UTxOState, VKey, VerKeyVRF) +import Numeric.Natural (Natural) import Tx (pattern TxOut) import TxData (pattern AddrBase, pattern KeyHashObj) +genBool :: Gen Bool +genBool = Gen.enumBounded + +genInteger :: Integer -> Integer -> Gen Integer +genInteger lower upper = Gen.integral $ Range.linear lower upper + +-- | Generator for a natural number between 'lower' and 'upper' +genNatural :: Natural -> Natural -> Gen Natural +genNatural lower upper = Gen.integral $ Range.linear lower upper + mkKeyPairs :: Word64 -> (KeyPair, KeyPair) mkKeyPairs n = (mkKeyPair_ (2*n), mkKeyPair_ (2*n+1)) @@ -38,7 +57,7 @@ mkKeyPairs n -- | Constant list of KeyPairs intended to be used in the generators. traceKeyPairs :: KeyPairs -traceKeyPairs = mkKeyPairs <$> [1 .. 50] +traceKeyPairs = mkKeyPairs <$> [1 .. 150] -- | Select between _lower_ and _upper_ keys from 'traceKeyPairs' someKeyPairs :: Int -> Int -> Gen KeyPairs @@ -71,10 +90,11 @@ genTxOut addrs = do -- | Generates a list of 'Coin' values of length between 'lower' and 'upper' -- and with values between 'minCoin' and 'maxCoin'. genCoinList :: Integer -> Integer -> Int -> Int -> Gen [Coin] -genCoinList minCoin maxCoin lower upper = do - xs <- Gen.list (Range.linear lower upper) - $ Gen.integral (Range.exponential minCoin maxCoin) - return (Coin <$> xs) +genCoinList minCoin maxCoin lower upper = + Gen.list (Range.linear lower upper) $ genCoin minCoin maxCoin + +genCoin :: Integer -> Integer -> Gen Coin +genCoin minCoin maxCoin = Coin <$> Gen.integral (Range.exponential minCoin maxCoin) genUtxo0 :: Int -> Int -> Gen UTxO genUtxo0 lower upper = do @@ -89,3 +109,27 @@ mkGenesisLedgerState _ = do utxo0 <- genUtxo0 5 10 let (LedgerState utxoSt dpSt _) = genesisState utxo0 pure (utxoSt, dpSt) + +-- | Generate values the given distribution in 90% of the cases, and values at +-- the bounds of the range in 10% of the cases. +-- +-- This can be used to generate enough extreme values. The exponential and +-- linear distributions provided by @hedgehog@ will generate a small percentage +-- of these (0-1%). +increasingProbabilityAt + :: Gen a + -> (a, a) + -> Gen a +increasingProbabilityAt gen (lower, upper) + = Gen.frequency [ (5, pure lower) + , (90, gen) + , (5, pure upper) + ] + +-- | A pre-populated space of VRF keys for use in the generators. +traceVRFKeyPairs :: [(SignKeyVRF, VerKeyVRF)] +traceVRFKeyPairs = [body (0,0,0,0,i) | i <- [1 .. 50]] + where + body seed = fst . withDRG (drgNewTest seed) $ do + sk <- genKeyVRF + return (sk, deriveVerKeyVRF sk) diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator/Delegation.hs b/shelley/chain-and-ledger/executable-spec/test/Generator/Delegation.hs index 95c0209c860..58e6239c648 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Generator/Delegation.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Generator/Delegation.hs @@ -1,88 +1,96 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE UndecidableInstances #-} module Generator.Delegation - ( genDCerts - , genPParams - ) + ( genDCerts ) where +import qualified Data.Map as Map +import Data.Ratio ((%)) import Data.Sequence (Seq) import qualified Data.Sequence as Seq +import qualified Data.Set as Set import Hedgehog (Gen) +import Lens.Micro (to, (^.)) import qualified Hedgehog.Gen as Gen import Coin (Coin (..)) -import Delegation.Certificates (pattern RegKey) +import Delegation.Certificates (pattern DeRegKey, pattern RegKey, pattern RegPool, + decayKey, isDeRegKey) import Examples (unsafeMkUnitInterval) -import Generator.Core (toCred) -import Ledger.Core (dom, (∉)) -import LedgerState (_dstate, _pstate, _stKeys, _stPools) -import MockTypes (DCert, DPState, DState, KeyPair, KeyPairs) -import PParams (PParams (..), emptyPParams) -import Slot (Epoch (..)) +import Generator.Core (genInteger, genNatural, toCred) +import Keys (hashKey, hashKeyVRF, vKey) +import Ledger.Core (dom, (∈), (∉)) +import LedgerState (dstate, keyRefund, pParams, pstate, stkCreds, _pstate, _stPools, + _stkCreds) +import MockTypes (DCert, DPState, DState, KeyPair, KeyPairs, PoolParams, VrfKeyPairs) +import Mutator (getAnyStakeKey) +import PParams (PParams (..)) +import Slot (Slot) +import TxData (Credential (KeyHashObj), pattern PoolParams, RewardAcnt (..), _poolPubKey, + _poolVrf) import UTxO (deposits) --- TODO @uroboros Generate a range of protocol params --- TODO @uroboros for now, keeping minA/B at zero until we generate fees in genTx -genPParams :: Gen PParams -genPParams = pure $ emptyPParams { - _minfeeA = 0 - , _minfeeB = 0 - , _maxBBSize = 50000 - , _maxBHSize = 10000 - , _maxTxSize = 10000 - , _eMax = Epoch 10000 - , _keyDeposit = Coin 7 - , _poolDeposit = Coin 250 - , _d = unsafeMkUnitInterval 0.5 - , _activeSlotCoeff = unsafeMkUnitInterval 0.1 - , _tau = unsafeMkUnitInterval 0.2 - , _rho = unsafeMkUnitInterval 0.0021 - , _keyDecayRate = 0.002 - , _keyMinRefund = unsafeMkUnitInterval 0.5 - , _poolDecayRate = 0.001 - , _poolMinRefund = unsafeMkUnitInterval 0.5 - } - -- | Generate certificates and also return the associated witnesses and --- total deposits required. +-- deposits and refunds required. genDCerts :: KeyPairs + -> VrfKeyPairs -> PParams -> DPState - -> Gen (Seq DCert, [KeyPair], Coin) -genDCerts keys pparams dpState = do + -> Slot + -> Gen (Seq DCert, [KeyPair], Coin, Coin) +genDCerts keys vrfKeys pparams dpState slotWithTTL = do -- TODO @uroboros Generate _multiple_ certs per Tx - cert <- genDCert keys (_dstate dpState) + -- TODO ensure that the `Seq` is constructed with the list reversed, or that + -- later traversals are done backwards, to be consistent with the executable + -- spec (see `delegsTransition` in `STS.Delegs`) which consumes the list + -- starting at the tail end. + cert <- genDCert keys vrfKeys dpState case cert of Nothing -> - return (Seq.empty, [], Coin 0) + return (Seq.empty, [], Coin 0, Coin 0) Just (cert_, witKey) -> do let certs = [cert_] witKeys = [witKey] + deposits_ = deposits pparams (_stPools (_pstate dpState)) certs - return (Seq.fromList certs, witKeys, deposits_) + deRegStakeCreds = filter isDeRegKey certs + rewardForCred crt = + let (dval, dmin, lambda) = decayKey pparams + in keyRefund dval + dmin + lambda + (dpState ^. dstate . stkCreds) + slotWithTTL + crt + refunds_ = sum (rewardForCred <$> deRegStakeCreds) + + return (Seq.fromList certs, witKeys, deposits_, refunds_) -- | Occasionally generate a valid certificate genDCert :: KeyPairs - -> DState + -> VrfKeyPairs + -> DPState -> Gen (Maybe (DCert, KeyPair)) -genDCert keys dState = - -- TODO @uroboros Generate _DeregKey_ Certificates - -- TODO @uroboros Generate _RegPool_ Certificates +genDCert keys vrfKeys dpState = -- TODO @uroboros Generate _RetirePool_ Certificates -- TODO @uroboros Generate _Delegate_ Certificates - Gen.frequency [ (25, genRegKeyCert keys dState) - , (75, pure Nothing) + Gen.frequency [ (3, genRegKeyCert keys dState) + , (3, genDeRegKeyCert keys dState) + , (3, genRegPool keys vrfKeys dpState) + , (1, pure Nothing) ] + where + dState = dpState ^. dstate -- | Generate a RegKey certificate along and also returns the stake key -- (needed to witness the certificate) @@ -97,5 +105,68 @@ genRegKeyCert keys delegSt = (_payKey, stakeKey) <- Gen.element availableKeys pure $ Just $ (RegKey (toCred stakeKey), stakeKey) where - notRegistered k = k ∉ dom (_stKeys delegSt) + notRegistered k = k ∉ dom (_stkCreds delegSt) availableKeys = filter (notRegistered . toCred . snd) keys + +-- | Generate a DeRegKey certificate along with the stake key, which is needed +-- to witness the certificate. +genDeRegKeyCert + :: KeyPairs + -> DState + -> Gen (Maybe (DCert, KeyPair)) +genDeRegKeyCert keys delegSt = + case availableKeys of + [] -> pure Nothing + _ -> do + (_payKey, stakeKey) <- Gen.element availableKeys + pure $ Just (DeRegKey (toCred stakeKey), stakeKey) + where + registered k = k ∈ dom (_stkCreds delegSt) + availableKeys = filter (registered . toCred . snd) keys + +-- | Generate and return a RegPool certificate along with its witnessing key. +genRegPool + :: KeyPairs + -> VrfKeyPairs + -> DPState + -> Gen (Maybe (DCert, KeyPair)) +genRegPool keys vrfKeys dpState = + if null availableKeys || null availableVrfKeys + then pure Nothing + else do + Just <$> genDCertRegPool availableKeys availableVrfKeys + where + notRegistered k = k `notElem` (dpState ^. pstate . pParams . to Map.elems . to (_poolPubKey <$>)) + availableKeys = filter (notRegistered . hashKey . vKey . snd) keys + + notRegisteredVrf k = k `notElem` (dpState ^. pstate . pParams . to Map.elems . to (_poolVrf <$>)) + availableVrfKeys = filter (notRegisteredVrf . hashKeyVRF . snd) vrfKeys + +-- | Generate PoolParams and the key witness. +genStakePool :: KeyPairs -> VrfKeyPairs -> Gen (PoolParams, KeyPair) +genStakePool skeys vrfKeys = + mkPoolParams + <$> (Gen.element skeys) + <*> (snd <$> Gen.element vrfKeys) + <*> (Coin <$> genInteger 1 100) + <*> (Coin <$> genInteger 1 100) + <*> (genNatural 0 100) + <*> (getAnyStakeKey skeys) + where + mkPoolParams poolKeyPair vrfKey cost pledge marginPercent acntKey = + let interval = unsafeMkUnitInterval $ fromIntegral marginPercent % 100 + pps = PoolParams + (hashKey . vKey . snd $ poolKeyPair) + (hashKeyVRF vrfKey) + pledge + cost + interval + (RewardAcnt $ KeyHashObj $ hashKey acntKey) + Set.empty + in (pps, snd poolKeyPair) + +-- | Generate `RegPool` and the key witness. +genDCertRegPool :: KeyPairs -> VrfKeyPairs -> Gen (DCert, KeyPair) +genDCertRegPool skeys vrfKeys = do + (pps, poolKey) <- genStakePool skeys vrfKeys + pure (RegPool pps, poolKey) diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator/LedgerTrace.hs b/shelley/chain-and-ledger/executable-spec/test/Generator/LedgerTrace.hs index 47ee81441a2..3524b70317a 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Generator/LedgerTrace.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Generator/LedgerTrace.hs @@ -15,8 +15,8 @@ import Cardano.Crypto.Hash (ShortHash) import Cardano.Crypto.VRF.Fake (FakeVRF) import Control.State.Transition.Generator (HasTrace, envGen, sigGen) -import Generator.Core (traceKeyPairs) -import Generator.Delegation (genPParams) +import Generator.Core (genCoin, traceKeyPairs, traceVRFKeyPairs) +import Generator.Update (genPParams) import Generator.Utxo (genTx) import Slot (Slot (..)) import STS.Ledger (LEDGER, LedgerEnv (..)) @@ -29,6 +29,7 @@ instance HasTrace (LEDGER ShortHash MockDSIGN FakeVRF) LedgerEnv <$> pure (Slot 0) <*> pure 0 <*> genPParams + <*> genCoin 0 1000 sigGen ledgerEnv ledgerSt = - genTx ledgerEnv ledgerSt traceKeyPairs + genTx ledgerEnv ledgerSt traceKeyPairs traceVRFKeyPairs diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator/Update.hs b/shelley/chain-and-ledger/executable-spec/test/Generator/Update.hs new file mode 100644 index 00000000000..6f37c09c21a --- /dev/null +++ b/shelley/chain-and-ledger/executable-spec/test/Generator/Update.hs @@ -0,0 +1,100 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE UndecidableInstances #-} + +module Generator.Update + ( genPParams ) + where + +import Data.Ratio ((%)) +import Hedgehog (Gen) + +import qualified Hedgehog.Gen as Gen + +import BaseTypes (Nonce (NeutralNonce), UnitInterval, mkNonce) +import Coin (Coin (..)) +import Examples (unsafeMkUnitInterval) +import Generator.Core (genInteger, genNatural, increasingProbabilityAt) +import qualified Hedgehog.Range as Range +import Numeric.Natural (Natural) +import PParams (PParams (..)) +import Slot (Epoch (Epoch)) + + +genRationalInThousands :: Integer -> Integer -> Gen Rational +genRationalInThousands lower upper = + (% 1000) <$> + Gen.integral (Range.linear lower upper) + +genIntervalInThousands :: Integer -> Integer -> Gen UnitInterval +genIntervalInThousands lower upper = + unsafeMkUnitInterval <$> genRationalInThousands lower upper + +-- TODO @uroboros for now, keeping minA/B at zero until we generate fees in genTx +genPParams :: Gen PParams +genPParams = mkPParams <$> pure 0 -- _minfeeA + <*> pure 0 -- _minfeeB + <*> szGen -- (maxBBSize, maxBHSize, maxTxSize) + -- keyDeposit + <*> increasingProbabilityAt + (Coin <$> genInteger 0 50) + (Coin 0, Coin 50) + -- keyMinRefund: 0.1-0.5 + <*> genIntervalInThousands 100 500 + -- keyDecayRate: 0.001-0.1 + <*> genRationalInThousands 1 100 + -- poolDeposit + <*> increasingProbabilityAt + (Coin <$> genInteger 0 500) + (Coin 0, Coin 500) + -- poolMinRefund: 0.1-0.7 + <*> genIntervalInThousands 100 700 + -- poolDecayRate: 0.001-0.1 + <*> genRationalInThousands 1 100 + -- eMax (for an epoch per 5 days, say, this is between a month and 7yrs) + <*> (Epoch <$> genNatural 6 500) + -- nOpt + <*> Gen.integral (Range.linear 1 100) + -- a0: 0.01-1.0 + <*> genRationalInThousands 10 1000 + -- rho: 0.001-0.009 + <*> genIntervalInThousands 1 9 + -- tau: 0.1-0.3 + <*> genIntervalInThousands 100 300 + -- activeSlotCoeff: 0-1 + <*> increasingProbabilityAt + (genIntervalInThousands 0 1000) + (unsafeMkUnitInterval 0, unsafeMkUnitInterval 1) + -- decentralisation param: 0,0.1,0.2..1 + <*> (unsafeMkUnitInterval <$> Gen.element [0, 0.1 .. 1]) + <*> genExtraEntropy + -- protocolVersion + <*> ((,,) <$> genNatural 1 10 <*> genNatural 1 50 <*> genNatural 1 100) + where + -- Note: we keep the lower bound high enough so that we can more likely + -- generate valid transactions and blocks + low = 10000 + hi = 200000 + + -- A wrapper to enable the dependent generators for the max sizes + mkPParams minFeeA minFeeB (maxBBSize, maxTxSize, maxBHSize) = + PParams minFeeA minFeeB maxBBSize maxTxSize maxBHSize + + -- | Generates max block, header and transaction size. First generates the + -- body size and then header and tx sizes no larger than half the body size. + szGen :: Gen (Natural, Natural, Natural) + szGen = do + blockBodySize <- Gen.integral (Range.linear low hi) + (blockBodySize,,) + <$> rangeUpTo (blockBodySize `div` 2) + <*> rangeUpTo (blockBodySize `div` 2) + + rangeUpTo :: Natural -> Gen Natural + rangeUpTo upper = Gen.integral (Range.linear low upper) + + -- Generates a Neutral or actual Nonces with equal frequency + genExtraEntropy = Gen.frequency [ (1, pure NeutralNonce) + , (1, mkNonce <$> Gen.integral (Range.linear 1 123))] diff --git a/shelley/chain-and-ledger/executable-spec/test/Generator/Utxo.hs b/shelley/chain-and-ledger/executable-spec/test/Generator/Utxo.hs index fd01854ba2c..7015941e273 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Generator/Utxo.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Generator/Utxo.hs @@ -24,7 +24,7 @@ import Generator.Core (findPayKeyPair, toAddr) import Generator.Delegation (genDCerts) import LedgerState (pattern UTxOState) import MockTypes (Addr, DCert, DPState, KeyPair, KeyPairs, Tx, TxBody, TxIn, TxOut, UTxO, - UTxOState) + UTxOState, VrfKeyPairs) import Slot (Slot (..)) import STS.Ledger (LedgerEnv (..)) import Tx (pattern Tx, pattern TxBody, pattern TxOut) @@ -38,8 +38,9 @@ import UTxO (pattern UTxO, balance, makeWitnessesVKey) genTx :: LedgerEnv -> (UTxOState, DPState) -> KeyPairs + -> VrfKeyPairs -> Gen Tx -genTx (LedgerEnv slot _ pparams) (UTxOState utxo _ _ _, dpState) keys = do +genTx (LedgerEnv slot _ pparams _) (UTxOState utxo _ _ _, dpState) keys vrfKeys = do keys' <- Gen.shuffle keys -- inputs @@ -49,18 +50,22 @@ genTx (LedgerEnv slot _ pparams) (UTxOState utxo _ _ _, dpState) keys = do -- output addresses recipientAddrs <- genRecipients keys' + ttl <- Gen.integral $ Range.linear 1 100 + let slotWithTTL = slot + Slot ttl + -- certificates - (certs, certWitnesses, deposits_) <- genDCerts keys' pparams dpState + (certs, certWitnesses, deposits_, refunds_) + <- genDCerts keys' vrfKeys pparams dpState slotWithTTL -- attempt to make provision for certificate deposits (otherwise discard this generator) when (spendingBalance < deposits_) Gen.discard - let balance_ = spendingBalance - deposits_ + let balance_ = spendingBalance - deposits_ + refunds_ -- calc. fees and output amounts let (fee, outputs) = calcFeeAndOutputs balance_ recipientAddrs -- witnessed transaction - txBody <- genTxBody (Set.fromList inputs) outputs certs fee slot + txBody <- genTxBody (Set.fromList inputs) outputs certs fee slotWithTTL let !wits = makeWitnessesVKey txBody (spendWitnesses ++ certWitnesses) multiSig = Map.empty -- TODO @uroboros Generate multi-sig transactions @@ -74,15 +79,14 @@ genTxBody -> Coin -> Slot -> Gen TxBody -genTxBody inputs outputs certs fee slot = do - ttl <- Gen.integral $ Range.linear 1 100 +genTxBody inputs outputs certs fee slotWithTTL = do return $ TxBody inputs outputs certs Map.empty -- TODO @uroboros generate withdrawals fee - (slot + Slot ttl) + slotWithTTL emptyUpdate -- TODO @uroboros generate updates -- | Calculate the fee and distribute the remainder of the balance diff --git a/shelley/chain-and-ledger/executable-spec/test/MockTypes.hs b/shelley/chain-and-ledger/executable-spec/test/MockTypes.hs index 9ab5999d454..61974307914 100644 --- a/shelley/chain-and-ledger/executable-spec/test/MockTypes.hs +++ b/shelley/chain-and-ledger/executable-spec/test/MockTypes.hs @@ -95,6 +95,8 @@ type SignKeyVRF = Keys.SignKeyVRF FakeVRF type VerKeyVRF = Keys.VerKeyVRF FakeVRF +type VrfKeyPairs = [(SignKeyVRF, VerKeyVRF)] + type CertifiedVRF = Keys.CertifiedVRF FakeVRF type KESig = Keys.KESig MockKES BHBody @@ -107,7 +109,7 @@ type OCert = OCert.OCert MockDSIGN MockKES type HashHeader = BlockChain.HashHeader ShortHash MockDSIGN MockKES FakeVRF -type NewEpochState = LedgerState.NewEpochState ShortHash MockDSIGN +type NewEpochState = LedgerState.NewEpochState ShortHash MockDSIGN FakeVRF type RewardUpdate = LedgerState.RewardUpdate ShortHash MockDSIGN @@ -136,7 +138,8 @@ type POOLREAP = STS.PoolReap.POOLREAP ShortHash MockDSIGN FakeVRF type Credential = TxData.Credential ShortHash MockDSIGN type StakeCredential = TxData.StakeCredential ShortHash MockDSIGN -type StakeKeys = TxData.StakeKeys ShortHash MockDSIGN + +type StakeCreds = TxData.StakeCreds ShortHash MockDSIGN type MultiSig = TxData.MultiSig ShortHash MockDSIGN diff --git a/shelley/chain-and-ledger/executable-spec/test/MultiSigExamples.hs b/shelley/chain-and-ledger/executable-spec/test/MultiSigExamples.hs index 0e3464d7b42..73ccca72e4b 100644 --- a/shelley/chain-and-ledger/executable-spec/test/MultiSigExamples.hs +++ b/shelley/chain-and-ledger/executable-spec/test/MultiSigExamples.hs @@ -21,7 +21,7 @@ import qualified Data.Set as Set (fromList) import Coin import Control.State.Transition (PredicateFailure, TRC (..), applySTS) -import Keys (pattern Dms, undiscriminateKeyHash) +import Keys (pattern GenDelegs, undiscriminateKeyHash) import LedgerState (genesisId, genesisCoins, genesisState, _utxoState) import MockTypes (Addr, KeyPair, LedgerState, MultiSig, ScriptHash, Tx, TxBody, TxId, TxIn, UTXOW, UTxOState, Wdrl) @@ -31,7 +31,7 @@ import STS.Utxo (UtxoEnv (..)) import Tx (hashScript) import TxData (pattern AddrBase, pattern KeyHashObj, pattern RequireAllOf, pattern RequireAnyOf, pattern RequireMOf, pattern RequireSignature, - pattern ScriptHashObj, pattern StakeKeys, pattern StakePools, pattern Tx, + pattern ScriptHashObj, pattern StakeCreds, pattern StakePools, pattern Tx, pattern TxBody, pattern TxIn, pattern TxOut, _body) import Updates (emptyUpdate) import UTxO (makeWitnessesVKey, txid) @@ -131,9 +131,9 @@ initialUTxOState aliceKeep msigs = (txid $ _body tx, applySTS @UTXOW (TRC( UtxoEnv (Slot 0) initPParams - (StakeKeys Map.empty) + (StakeCreds Map.empty) (StakePools Map.empty) - (Dms Map.empty) + (GenDelegs Map.empty) , _utxoState genesis , tx))) @@ -168,8 +168,8 @@ applyTxWithScript lockScripts unlockScripts wdrl aliceKeep signers = utxoSt' utxoSt' = applySTS @UTXOW (TRC( UtxoEnv (Slot 0) initPParams - (StakeKeys Map.empty) + (StakeCreds Map.empty) (StakePools Map.empty) - (Dms Map.empty) + (GenDelegs Map.empty) , utxoSt , tx)) diff --git a/shelley/chain-and-ledger/executable-spec/test/Mutator.hs b/shelley/chain-and-ledger/executable-spec/test/Mutator.hs index 628d25699cd..5d0879b3e33 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Mutator.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Mutator.hs @@ -17,6 +17,8 @@ module Mutator , getAnyStakeKey ) where +import qualified Data.List as List (map) +import qualified Data.Map.Strict as Map (fromList, toList) import Data.Maybe (fromMaybe) import Data.Ratio import Data.Set as Set @@ -29,7 +31,8 @@ import qualified Hedgehog.Range as Range import BaseTypes import Coin import Delegation.Certificates (pattern DeRegKey, pattern Delegate, - pattern GenesisDelegate, pattern RegKey, pattern RegPool, pattern RetirePool) + pattern GenesisDelegate, pattern InstantaneousRewards, pattern RegKey, + pattern RegPool, pattern RetirePool) import Keys (hashKey, vKey) import Updates @@ -178,3 +181,9 @@ mutateDCert keys _ (Delegate (Delegation _ _)) = do mutateDCert keys _ (GenesisDelegate (gk, _)) = do _delegatee <- getAnyStakeKey keys pure $ GenesisDelegate (gk, hashKey _delegatee) + +mutateDCert _ _ (InstantaneousRewards credCoinMap) = do + let credCoinList = Map.toList credCoinMap + coins = List.map snd credCoinList + coins' <- mapM (mutateCoin 1 100) coins + pure $ InstantaneousRewards $ Map.fromList $ zip (List.map fst credCoinList) coins' diff --git a/shelley/chain-and-ledger/executable-spec/test/PropertyTests.hs b/shelley/chain-and-ledger/executable-spec/test/PropertyTests.hs index c4062b6d143..d2cde309fb2 100644 --- a/shelley/chain-and-ledger/executable-spec/test/PropertyTests.hs +++ b/shelley/chain-and-ledger/executable-spec/test/PropertyTests.hs @@ -21,10 +21,11 @@ import qualified Hedgehog.Gen as Gen import Coin import Ledger.Core ((<|)) -import LedgerState hiding (dms) +import LedgerState hiding (genDelegs) import PParams -import Rules.TestLedger (rewardZeroAfterReg) -import Rules.ClassifyTraces (relevantCasesAreCovered) +import Rules.ClassifyTraces (onlyValidLedgerSignalsAreGenerated, relevantCasesAreCovered) +import Rules.TestLedger (credentialRemovedAfterDereg, pStateIsInternallyConsistent, + registeredPoolIsAdded, rewardZeroAfterReg) import Slot import Tx (pattern TxIn, pattern TxOut, body, certs, inputs, outputs, witnessVKeySet, _body, _witnessVKeySet) @@ -157,7 +158,17 @@ propertyTests = testGroup "Property-Based Testing" [ testGroup "Classify Traces" [testProperty "Ledger trace covers the relevant cases" relevantCasesAreCovered] , testGroup "STS Rules - Delegation Properties" - [testProperty "newly registered key has a reward of 0" rewardZeroAfterReg] + [ testProperty "newly registered key has a reward of 0" rewardZeroAfterReg + , testProperty "deregistered key's credential is removed" + credentialRemovedAfterDereg + ] + , testGroup "STS Rules - Pool Properties" + [ testProperty "newly registered stake pool is added to \ + \appropriate state mappings" + registeredPoolIsAdded + , testProperty "pool state is internally consistent" + pStateIsInternallyConsistent + ] , testGroup "Ledger Genesis State" [testProperty "non-empty genesis ledger state has non-zero balance" @@ -199,6 +210,11 @@ propertyTests = testGroup "Property-Based Testing" "Classify double spend" classifyInvalidDoubleSpend ] + , testGroup "Properties of Trace generators" + [testProperty + "Only valid LEDGER STS signals are generated" + onlyValidLedgerSignalsAreGenerated + ] ] -- | Mutations for Property 7.2 @@ -243,8 +259,8 @@ propCheckRedundantWitnessSet = property $ do let tx = txwits ^. body let witness = makeWitnessVKey tx keyPair let txwits' = txwits & witnessVKeySet %~ Set.insert witness - let dms = _dms $ _dstate $ _delegationState l - let l'' = asStateTransition (Slot steps) emptyPParams l txwits' dms + let genDelegs = _genDelegs $ _dstate $ _delegationState l + let l'' = asStateTransition (Slot steps) emptyPParams l txwits' genDelegs classify "unneeded signature added" (not $ witness `Set.member` (txwits ^. witnessVKeySet)) case l'' of @@ -261,8 +277,8 @@ propCheckMissingWitness = property $ do Set.toList (txwits ^. witnessVKeySet)) let witnessVKeySet'' = txwits ^. witnessVKeySet let witnessVKeySet' = Set.fromList witnessList - let dms = _dms $ _dstate $ _delegationState l - let l' = asStateTransition (Slot steps) emptyPParams l (txwits & witnessVKeySet .~ witnessVKeySet') dms + let genDelegs = _genDelegs $ _dstate $ _delegationState l + let l' = asStateTransition (Slot steps) emptyPParams l (txwits & witnessVKeySet .~ witnessVKeySet') genDelegs let isRealSubset = witnessVKeySet' `Set.isSubsetOf` witnessVKeySet'' && witnessVKeySet' /= witnessVKeySet'' classify "real subset" isRealSubset @@ -278,7 +294,7 @@ propPreserveBalance = property $ do (l, _, fee, tx, l') <- forAll genValidStateTx let destroyed = balance (l ^. utxoState . utxo) - + (keyRefunds emptyPParams (l ^. delegationState . dstate . stKeys) $ tx ^. body) + + (keyRefunds emptyPParams (l ^. delegationState . dstate . stkCreds) $ tx ^. body) let created = balance (l' ^. utxoState . utxo) + fee diff --git a/shelley/chain-and-ledger/executable-spec/test/Rules/ClassifyTraces.hs b/shelley/chain-and-ledger/executable-spec/test/Rules/ClassifyTraces.hs index 8b8eea0ba57..9d34dbeba00 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Rules/ClassifyTraces.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Rules/ClassifyTraces.hs @@ -2,21 +2,24 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TypeApplications #-} -module Rules.ClassifyTraces where +module Rules.ClassifyTraces + ( onlyValidLedgerSignalsAreGenerated + , relevantCasesAreCovered) + where import Data.Foldable (toList) -import qualified Data.Set as Set import Hedgehog (Property, cover, forAll, property, withTests) -import Control.State.Transition.Generator (traceOfLengthWithInitState) +import Control.State.Transition.Generator (onlyValidSignalsAreGeneratedForTrace, + traceOfLengthWithInitState) import Control.State.Transition.Trace (TraceOrder (OldestFirst), traceLength, traceSignals) -import Delegation.Certificates (pattern RegKey) +import Delegation.Certificates (isDeRegKey, isRegKey, isRegPool) import Generator.Core (mkGenesisLedgerState) import Generator.LedgerTrace () import MockTypes (DCert, LEDGER, Tx) -import TxData (_body, _certs, _inputs, _outputs) +import TxData (_body, _certs) relevantCasesAreCovered :: Property relevantCasesAreCovered = withTests 500 $ property $ do @@ -34,13 +37,21 @@ relevantCasesAreCovered = withTests 500 $ property $ do "there is at least 1 RegKey certificate for every 5 transactions" (traceLength tr <= 5 * length (filter isRegKey certs_)) + cover 75 + "there is at least 1 DeRegKey certificate for every 5 transactions" + (traceLength tr <= 5 * length (filter isDeRegKey certs_)) + + cover 75 + "there is at least 1 RegPool certificate for every 20 transactions" + (traceLength tr <= 20 * length (filter isRegPool certs_)) + cover 25 "at most 75% of transactions have no certificates" (0.75 >= noCertsRatio (certsByTx txs)) -- | Extract the certificates from the transactions certsByTx :: [Tx] -> [[DCert]] -certsByTx txs = (toList . _certs . _body) <$> txs +certsByTx txs = toList . _certs . _body <$> txs -- | Flattended list of DCerts for the given transactions allCerts :: [Tx] -> [DCert] @@ -50,21 +61,6 @@ allCerts = concat . certsByTx noCertsRatio :: [[DCert]] -> Double noCertsRatio = lenRatio (filter null) -isRegKey :: DCert -> Bool -isRegKey (RegKey _) = True -isRegKey _ = False - --- | Returns the average number of inputs and outputs for a list of transactions. -avgInputsOutputs :: [Tx] -> (Double, Double) -avgInputsOutputs txs - = case length txs of - 0 -> (0,0) - n -> ( nrInputs / fromIntegral n - , nrOutputs / fromIntegral n) - where - nrInputs = fromIntegral $ sum (Set.size . _inputs . _body <$> txs) - nrOutputs = fromIntegral $ sum (length . _outputs . _body <$> txs) - ratioInt :: Int -> Int -> Double ratioInt x y = fromIntegral x / fromIntegral y @@ -75,3 +71,10 @@ lenRatio :: ([a] -> [b]) -> [a] -> Double lenRatio f xs = ratioInt (length (f xs)) (length xs) + +onlyValidLedgerSignalsAreGenerated :: Property +onlyValidLedgerSignalsAreGenerated = + withTests 200 $ + onlyValidSignalsAreGeneratedForTrace traceGen + where + traceGen = traceOfLengthWithInitState @LEDGER 100 mkGenesisLedgerState diff --git a/shelley/chain-and-ledger/executable-spec/test/Rules/TestDeleg.hs b/shelley/chain-and-ledger/executable-spec/test/Rules/TestDeleg.hs index 9444974262c..d110b106d24 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Rules/TestDeleg.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Rules/TestDeleg.hs @@ -30,7 +30,7 @@ import Generator.LedgerTrace () import Ledger.Core (dom, range, (∈), (∉), (◁)) import Coin (Coin, pattern Coin) -import LedgerState (_delegations, _rewards, _stKeys) +import LedgerState (_delegations, _rewards, _stkCreds) import MockTypes (DELEG, DState, KeyHash, RewardAcnt, StakeCredential) import Test.Utils (assertAll) import TxData (pattern DeRegKey, pattern Delegate, pattern Delegation, pattern RegKey) @@ -40,7 +40,7 @@ import TxData (pattern DeRegKey, pattern Delegate, pattern Delegation, ------------------------------- getStDelegs :: DState -> Set StakeCredential -getStDelegs = dom . _stKeys +getStDelegs = dom . _stkCreds getRewards :: DState -> Map RewardAcnt Coin getRewards = _rewards @@ -78,11 +78,11 @@ rewardZeroAfterReg tr = -- | Check that when a stake credential is deregistered, it will not be in the -- rewards mapping or delegation mapping of the target state. -credentialRemovedAfterDereg :: Property -credentialRemovedAfterDereg = withTests numberOfTests . property $ do - tr <- fmap sourceSignalTargets - $ forAll - $ trace @DELEG traceLen `ofLengthAtLeast` 1 +credentialRemovedAfterDereg + :: MonadTest m + => [SourceSignalTarget DELEG] + -> m () +credentialRemovedAfterDereg tr = do assertAll removedDeregCredential tr where removedDeregCredential (SourceSignalTarget diff --git a/shelley/chain-and-ledger/executable-spec/test/Rules/TestDelegs.hs b/shelley/chain-and-ledger/executable-spec/test/Rules/TestDelegs.hs index cdf9c260ab6..4f322fe0e04 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Rules/TestDelegs.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Rules/TestDelegs.hs @@ -42,7 +42,7 @@ rewardsDecreasesByWithdrawals :: Property rewardsDecreasesByWithdrawals = withTests numberOfTests . property $ do t <- forAll $ trace @DELEGS traceLen `ofLengthAtLeast` 1 - let DelegsEnv _ _ _ tx = _traceEnv t + let DelegsEnv _ _ _ tx _ = _traceEnv t tr = sourceSignalTargets t assertAll (rewardsPotdecreases $ _body tx) tr diff --git a/shelley/chain-and-ledger/executable-spec/test/Rules/TestLedger.hs b/shelley/chain-and-ledger/executable-spec/test/Rules/TestLedger.hs index c0c1e00efa2..fbb5a94ebee 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Rules/TestLedger.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Rules/TestLedger.hs @@ -5,28 +5,33 @@ module Rules.TestLedger ( rewardZeroAfterReg + , credentialRemovedAfterDereg , consumedEqualsProduced + , registeredPoolIsAdded + , pStateIsInternallyConsistent ) where import Data.Foldable (toList) import Data.Word (Word64) +import Lens.Micro ((^.)) import Hedgehog (Property, forAll, property, withTests) import Control.State.Transition.Generator (ofLengthAtLeast, trace, traceOfLengthWithInitState) -import Control.State.Transition.Trace (SourceSignalTarget, pattern SourceSignalTarget, - source, sourceSignalTargets, target) +import Control.State.Transition.Trace (SourceSignalTarget (..), source, + sourceSignalTargets, target, traceEnv) import Generator.Core (mkGenesisLedgerState) import Generator.LedgerTrace () import Coin (pattern Coin) import LedgerState (pattern DPState, pattern DState, pattern UTxOState, _deposited, _dstate, _fees, _rewards, _utxo) -import MockTypes (DELEG, LEDGER) +import MockTypes (DELEG, LEDGER, POOL) import qualified Rules.TestDeleg as TestDeleg -import TxData (_body, _certs) +import qualified Rules.TestPool as TestPool +import TxData (body, certs) import UTxO (balance) import Test.Utils (assertAll) @@ -54,13 +59,21 @@ rewardZeroAfterReg = withTests (fromIntegral numberOfTests) . property $ do mkGenesisLedgerState `ofLengthAtLeast` 1) - TestDeleg.rewardZeroAfterReg ((concatMap toCerts . sourceSignalTargets) t) + TestDeleg.rewardZeroAfterReg + ((concatMap ledgerToDelegSsts . sourceSignalTargets) t) - where toCerts - :: SourceSignalTarget LEDGER - -> [SourceSignalTarget DELEG] - toCerts (SourceSignalTarget (_, DPState d _) (_, DPState d' _) tx) = - [SourceSignalTarget d d' cert | cert <- toList . _certs . _body $ tx] + +credentialRemovedAfterDereg :: Property +credentialRemovedAfterDereg = + withTests (fromIntegral numberOfTests) . property $ do + tr <- fmap sourceSignalTargets + $ forAll + $ traceOfLengthWithInitState @LEDGER + (fromIntegral traceLen) + mkGenesisLedgerState + `ofLengthAtLeast` 1 + TestDeleg.credentialRemovedAfterDereg + (concatMap ledgerToDelegSsts tr) -- | Check that the value consumed by UTXO is equal to the value produced in @@ -93,3 +106,45 @@ consumedEqualsProduced = withTests (fromIntegral numberOfTests) . property $ do (balance u + d + fees + foldl (+) (Coin 0) rewards ) == (balance u' + d' + fees' + foldl (+) (Coin 0) rewards') + + +-- | Check that a `RegPool` certificate properly adds a stake pool. +registeredPoolIsAdded :: Property +registeredPoolIsAdded = do + withTests (fromIntegral numberOfTests) . property $ do + tr <- forAll + $ traceOfLengthWithInitState @LEDGER + (fromIntegral traceLen) + mkGenesisLedgerState + `ofLengthAtLeast` 1 + TestPool.registeredPoolIsAdded + (tr ^. traceEnv) + (concatMap ledgerToPoolSsts (sourceSignalTargets tr)) + + +pStateIsInternallyConsistent :: Property +pStateIsInternallyConsistent = do + withTests (fromIntegral numberOfTests) . property $ do + tr <- forAll + $ traceOfLengthWithInitState @LEDGER + (fromIntegral traceLen) + mkGenesisLedgerState + `ofLengthAtLeast` 1 + TestPool.pStateIsInternallyConsistent + (concatMap ledgerToPoolSsts (sourceSignalTargets tr)) + + +-- | Transform LEDGER `sourceSignalTargets`s to DELEG ones. +ledgerToDelegSsts + :: SourceSignalTarget LEDGER + -> [SourceSignalTarget DELEG] +ledgerToDelegSsts (SourceSignalTarget (_, DPState d _) (_, DPState d' _) tx) = + [SourceSignalTarget d d' cert | cert <- toList (tx ^. body . certs)] + + +-- | Transform LEDGER `SourceSignalTargets`s to POOL ones. +ledgerToPoolSsts + :: SourceSignalTarget LEDGER + -> [SourceSignalTarget POOL] +ledgerToPoolSsts (SourceSignalTarget (_, DPState _ p) (_, DPState _ p') tx) = + [SourceSignalTarget p p' cert | cert <- toList (tx ^. body . certs)] diff --git a/shelley/chain-and-ledger/executable-spec/test/Rules/TestPool.hs b/shelley/chain-and-ledger/executable-spec/test/Rules/TestPool.hs index 2c35a8cdab3..9096a69bee0 100644 --- a/shelley/chain-and-ledger/executable-spec/test/Rules/TestPool.hs +++ b/shelley/chain-and-ledger/executable-spec/test/Rules/TestPool.hs @@ -1,30 +1,37 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeSynonymInstances #-} module Rules.TestPool where +import Data.Foldable (traverse_) import Data.Map (Map, (!?)) +import qualified Data.Map as M import qualified Data.Maybe as Maybe (maybe) +import qualified Data.Set as S import Data.Word (Word64) +import Lens.Micro (to, (^.)) -import Hedgehog (Property, forAll, property, withTests) +import Hedgehog (MonadTest, Property, assert, forAll, property, withTests, (===)) +import Control.State.Transition (Environment, State) import Control.State.Transition.Generator (ofLengthAtLeast, trace) -import Control.State.Transition.Trace (pattern SourceSignalTarget, signal, source, - sourceSignalTargets, target, _traceEnv) +import Control.State.Transition.Trace (SourceSignalTarget, pattern SourceSignalTarget, + signal, source, sourceSignalTargets, target, _traceEnv) import BaseTypes ((==>)) import Delegation.Certificates (cwitness) -import LedgerState (_retiring, _stPools) -import MockTypes (KeyHash, POOL, PState, StakePools) +import LedgerState (pattern PState, cCounters, pParams, stPools, _retiring, _stPools) +import MockTypes (KeyHash, LEDGER, POOL, PState, PoolParams, StakePools) import PParams (_eMax) import Slot (Epoch (..), epochFromSlot) +import STS.Ledger (LedgerEnv (ledgerSlot)) import STS.Pool (PoolEnv (..)) import TxData (pattern KeyHashObj, pattern RegPool, pattern RetirePool, - pattern StakePools) + pattern StakePools, poolPubKey) import Ledger.Core (dom, (∈), (∉)) @@ -102,3 +109,58 @@ poolRetireInEpoch = withTests (fromIntegral numberOfTests) . property $ do && Maybe.maybe False ((== e) . epochFromSlot) (stp' !? certWit)) _ -> False registeredPoolRetired _ _ _ = True + +-- | Check that a `RegPool` certificate properly adds a stake pool. +registeredPoolIsAdded + :: MonadTest m + => Environment LEDGER + -> [SourceSignalTarget POOL] + -> m () +registeredPoolIsAdded env ssts = + assertAll addedRegPool ssts + + where + + addedRegPool :: SourceSignalTarget POOL + -> Bool + addedRegPool sst = + case signal sst of + RegPool poolParams -> check poolParams + _ -> True + where + check :: PoolParams -> Bool + check poolParams = + let hk = poolParams ^. poolPubKey + pSt = target sst + -- PoolParams are registered in pParams map + in M.lookup hk (pSt ^. pParams) == Just poolParams + -- Hashkey is registered in stPools map + && M.lookup hk (pSt ^. stPools . to (\(StakePools x) -> x)) + == Just (ledgerSlot env) + -- Hashkey is registered in cCounters map + && hk ∈ M.keys (pSt ^. cCounters) + +-- | Assert that PState maps are in sync with each other after each `Signal +-- POOL` transition. +pStateIsInternallyConsistent + :: forall m + . MonadTest m + => [SourceSignalTarget POOL] + -> m () +pStateIsInternallyConsistent ssts = + traverse_ isConsistent (concatMap (\sst -> [source sst, target sst]) ssts) + where + isConsistent :: State POOL -> m () + isConsistent (PState stPools_ pParams_ retiring_ cCounters_) = do + let StakePools stPoolsMap = stPools_ + poolKeys = M.keysSet stPoolsMap + pParamKeys = M.keysSet pParams_ + retiringKeys = M.keys retiring_ + cCountersKeys = M.keysSet cCounters_ + + sequence_ [ -- These 3 key sets should be equal. + poolKeys === pParamKeys + , pParamKeys === cCountersKeys + -- A retiring pool should still be registered in `stPools`. + , traverse_ (assert . (`S.member` poolKeys)) retiringKeys + ] diff --git a/shelley/chain-and-ledger/executable-spec/test/STSTests.hs b/shelley/chain-and-ledger/executable-spec/test/STSTests.hs index 23561dac273..a259e02cfe4 100644 --- a/shelley/chain-and-ledger/executable-spec/test/STSTests.hs +++ b/shelley/chain-and-ledger/executable-spec/test/STSTests.hs @@ -6,16 +6,17 @@ module STSTests (stsTests) where import Data.Either (isRight) import qualified Data.Map.Strict as Map (empty, singleton) import Test.Tasty (TestTree, testGroup) -import Test.Tasty.HUnit (Assertion, assertBool, testCase, (@?=)) +import Test.Tasty.HUnit (Assertion, assertBool, assertFailure, testCase, (@?=)) import Examples (CHAINExample (..), alicePay, bobPay, carlPay, dariaPay, ex1, ex2A, ex2B, ex2C, ex2Cbis, ex2Cquater, ex2Cter, ex2D, ex2E, ex2F, ex2G, ex2H, ex2I, ex2J, - ex2K, ex2L, ex3A, ex3B, ex3C, ex4A, ex4B, ex4C, ex5A, ex5B, maxLovelaceSupply) + ex2K, ex2L, ex3A, ex3B, ex3C, ex4A, ex4B, ex4C, ex5A, ex5B, ex6A, ex6B, ex6C, + ex6D, ex6E, maxLovelaceSupply) import MockTypes (CHAIN) import MultiSigExamples (aliceAndBob, aliceAndBobOrCarl, aliceAndBobOrCarlAndDaria, aliceAndBobOrCarlOrDaria, aliceOnly, aliceOrBob, applyTxWithScript, bobOnly) -import BaseTypes ((⭒), mkNonce) +import BaseTypes (mkNonce, (⭒)) import Control.State.Transition (TRC (..), applySTS) import Control.State.Transition.Trace (checkTrace, (.-), (.->)) import Slot (Slot (..)) @@ -49,12 +50,18 @@ testUPNLate = st @?= Right (UpdnState ((mkNonce 2) ⭒ (mkNonce 1)) (mkNonce 3)) testCHAINExample :: CHAINExample -> Assertion -testCHAINExample (CHAINExample slotNow initSt block expectedSt) = do +testCHAINExample (CHAINExample slotNow initSt block (Right expectedSt)) = do checkTrace @CHAIN slotNow $ pure initSt .- block .-> expectedSt +testCHAINExample (CHAINExample slotNow initSt block predicateFailure@(Left _)) = do + let + st = applySTS @CHAIN (TRC (slotNow, initSt, block)) + st @?= predicateFailure testPreservationOfAda :: CHAINExample -> Assertion -testPreservationOfAda (CHAINExample _ _ _ expectedSt) = +testPreservationOfAda (CHAINExample _ _ _ (Right expectedSt)) = totalAda expectedSt @?= maxLovelaceSupply +testPreservationOfAda (CHAINExample _ _ _ (Left predicateFailure)) = + assertFailure $ "Ada not preserved " ++ show predicateFailure stsTests :: TestTree stsTests = testGroup "STS Tests" @@ -84,6 +91,11 @@ stsTests = testGroup "STS Tests" , testCase "CHAIN example 4C - adopt a future app version" $ testCHAINExample ex4C , testCase "CHAIN example 5A - stage genesis key delegation" $ testCHAINExample ex5A , testCase "CHAIN example 5B - adopt genesis key delegation" $ testCHAINExample ex5B + , testCase "CHAIN example 6A - create MIR cert" $ testCHAINExample ex6A + , testCase "CHAIN example 6B - FAIL: insufficient core node signatures" $ testCHAINExample ex6B + , testCase "CHAIN example 6C - FAIL: MIR impossible in decentralized network" $ testCHAINExample ex6C + , testCase "CHAIN example 6D - FAIL: MIR impossible (decentralized and insufficient sigs)" $ testCHAINExample ex6D + , testCase "CHAIN example 6E - FAIL: MIR insufficient reserves" $ testCHAINExample ex6E , testCase "CHAIN example 1 - Preservation of ADA" $ testPreservationOfAda ex1 , testCase "CHAIN example 2A - Preservation of ADA" $ testPreservationOfAda ex2A , testCase "CHAIN example 2B - Preservation of ADA" $ testPreservationOfAda ex2B diff --git a/shelley/chain-and-ledger/executable-spec/test/UnitTests.hs b/shelley/chain-and-ledger/executable-spec/test/UnitTests.hs index 4efe6dea034..62253b760dd 100644 --- a/shelley/chain-and-ledger/executable-spec/test/UnitTests.hs +++ b/shelley/chain-and-ledger/executable-spec/test/UnitTests.hs @@ -20,16 +20,16 @@ import BaseTypes import qualified Cardano.Crypto.VRF.Fake as FakeVRF import Coin import Delegation.Certificates (pattern Delegate, pattern RegKey, pattern RegPool, - pattern RetirePool, StakeKeys (..), StakePools (..)) + pattern RetirePool, StakeCreds (..), StakePools (..)) import TxData (pattern AddrBase, Credential (..), Delegation (..), pattern PoolParams, pattern Ptr, pattern RewardAcnt, _poolCost, _poolMargin, _poolOwners, _poolPledge, _poolPubKey, _poolRAcnt, _poolVrf) -import Keys (pattern Dms, pattern KeyPair, hashKey, hashKeyVRF, vKey) +import Keys (pattern GenDelegs, pattern KeyPair, hashKey, hashKeyVRF, vKey) import LedgerState (pattern LedgerState, pattern UTxOState, ValidationError (..), asStateTransition, cCounters, delegationState, delegations, dstate, emptyDelegation, genesisId, genesisCoins, genesisState, minfee, pParams, pstate, ptrs, - retiring, rewards, stKeys, stPools, _delegationState, _dms, _dstate) + retiring, rewards, stkCreds, stPools, _delegationState, _genDelegs, _dstate) import PParams import Slot import Tx (pattern Tx, pattern TxBody, pattern TxIn, pattern TxOut, body, ttl) @@ -90,8 +90,8 @@ stakePoolVRFKey1 = FakeVRF.VerKeyFakeVRF 15 ledgerState :: [Tx] -> Either [ValidationError] LedgerState -ledgerState = foldM (\l t -> asStateTransition (Slot 0) testPCs l t dms') genesis - where dms' = _dms $ _dstate $ _delegationState genesis +ledgerState = foldM (\l t -> asStateTransition (Slot 0) testPCs l t genDelegs') genesis + where genDelegs' = _genDelegs $ _dstate $ _delegationState genesis testLedgerValidTransactions :: @@ -170,7 +170,7 @@ testValidWithdrawal = [ (TxIn genesisId 1, TxOut bobAddr (Coin 1000)) , (TxIn (txid tx) 0, TxOut aliceAddr (Coin 6000)) , (TxIn (txid tx) 1, TxOut bobAddr (Coin 3010)) ] - ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (Dms Map.empty) + ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (GenDelegs Map.empty) expectedDS = LedgerState.emptyDelegation & dstate . rewards .~ Map.singleton (mkVKeyRwdAcnt bobStake) (Coin 0) in ls @?= Right (LedgerState @@ -207,7 +207,7 @@ testWithdrawalNoWit = (Slot 0) emptyUpdate wits = Set.singleton $ makeWitnessVKey tx alicePay - ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (Dms Map.empty) + ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (GenDelegs Map.empty) in ls @?= Left [MissingWitnesses] testWithdrawalWrongAmt :: Assertion @@ -223,7 +223,7 @@ testWithdrawalWrongAmt = (Slot 0) emptyUpdate wits = makeWitnessesVKey tx [alicePay, bobStake] - ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (Dms Map.empty) + ls = asStateTransition (Slot 0) testPCs genesisWithReward (Tx tx wits Map.empty) (GenDelegs Map.empty) in ls @?= Left [IncorrectRewards] aliceGivesBobLovelace :: TxIn -> Coin -> Coin -> Coin -> Coin -> @@ -318,7 +318,7 @@ stakeKeyRegistration1 = LedgerState.emptyDelegation Map.fromList [ (mkVKeyRwdAcnt aliceStake, Coin 0) , (mkVKeyRwdAcnt bobStake, Coin 0) , (mkVKeyRwdAcnt stakePoolKey1, Coin 0)] - & dstate . stKeys .~ (StakeKeys $ + & dstate . stkCreds .~ (StakeCreds $ Map.fromList [ (KeyHashObj $ hashKey $ vKey aliceStake, Slot 0) , (KeyHashObj $ hashKey $ vKey bobStake, Slot 0) , (KeyHashObj $ hashKey $ vKey stakePoolKey1, Slot 0)]) @@ -504,7 +504,7 @@ testEmptyInputSet = emptyUpdate wits = makeWitnessesVKey tx [aliceStake] genesisWithReward' = changeReward genesis (mkVKeyRwdAcnt aliceStake) (Coin 2000) - ls = asStateTransition (Slot 0) testPCs genesisWithReward' (Tx tx wits Map.empty) (Dms Map.empty) + ls = asStateTransition (Slot 0) testPCs genesisWithReward' (Tx tx wits Map.empty) (GenDelegs Map.empty) in ls @?= Left [ InputSetEmpty ] testFeeTooSmall :: Assertion @@ -528,7 +528,7 @@ testExpiredTx = [] (Slot 0) [alicePay] - in asStateTransition (Slot 1) testPCs genesis tx (Dms Map.empty) @?= + in asStateTransition (Slot 1) testPCs genesis tx (GenDelegs Map.empty) @?= Left [ Expired (Slot 0) (Slot 1) ] testsInvalidLedger :: TestTree diff --git a/shelley/chain-and-ledger/formal-spec/Properties.md b/shelley/chain-and-ledger/formal-spec/Properties.md index f103890dd9e..d06fd117bd4 100644 --- a/shelley/chain-and-ledger/formal-spec/Properties.md +++ b/shelley/chain-and-ledger/formal-spec/Properties.md @@ -1,3 +1,12 @@ +# Ledger and Epoch State Validity + +We only care that the properties below are satisfied for _valid_ ledger states, and +more generally, valid _epoch_ states. Checking things for invalid states should +not be performed. As the STS rule system we have defined +is deterministic, all valid states can be reached using the transitions in the system, +and the only states that are valid are those that can be described by a sequence +of rule applications (i.e. a composition of valid transitions). + # Preservation of Value Recall that there are six pots of money in the Shelley ledger: @@ -9,9 +18,9 @@ Recall that there are six pots of money in the Shelley ledger: * Reserves * Treasury -For each transition sytem, we will list what pots are in scope, +For each transition system, we will list what pots are in scope, describe how value moves between the pots, -and state any relevent properties (usually the preservation of ADA). +and state any relevant properties (usually the preservation of ADA). ### Transitions with no pots in scope @@ -28,8 +37,8 @@ and state any relevent properties (usually the preservation of ADA). Pots in scope: Circulation, Deposits, Fees -Value can be transfered between Circulation and Deposits. -Value can also be transfered to the Fees, but Fees can only +Value can be transferred between Circulation and Deposits. +Value can also be transferred to the Fees, but Fees can only be increased by this transition. **Property** The value (Circulation + Deposits + Fees) increases by the sum @@ -106,7 +115,7 @@ the fee pot. Pots in scope: Circulation, Deposits, Fees, Treasury, Reserves -The new protocol parameter transition adusts the deposit pot to meet +The new protocol parameter transition adjusts the deposit pot to meet the current obligation, and the difference is made up by the reserves. **Property** The value (Deposits + Reserves) is the same @@ -166,10 +175,10 @@ If there are no pending future application versions, there will not be a change to the version for at least SlotsPerEpoch. **Property** -Updating the sofware versions, without updating the protocol version, +Updating the software versions, without updating the protocol version, results in no change to the transition systems. Note that changes to the transition system resulting from a new -protocol version will be difficult to state formally, since this +protocol version will be difficult to state formally, since this depends on logic in the software changing the ledger rules. **Definition** @@ -181,15 +190,15 @@ Let **quorum** be the number of genesis nodes needed for consensus on votes (concretely this value is five). **Property** -If there are only (quorum -1)-many gen keys acive, there can be no new future +If there are only (quorum -1)-many gen keys active, there can be no new future application version or protocol parameters. **Property** **Property** The keys (of type Slot) of the following two mappings are always past the current slot: -the future application versions (favs) and the future genesis delegation mapping (fdms). -The favs slots can appear in any current or future epoch, but the fdms slots +the future application versions (favs) and the future genesis delegation mapping (fGenDelegs). +The favs slots can appear in any current or future epoch, but the fGenDelegs slots can be at most one epoch into the future. **Property** @@ -198,6 +207,18 @@ The size of the mappings PPUpdate, inside the update state, is always at most (n **Property** The size of the mappings AVUpdate, inside the update state, is always at most num-genesis. +# Epoch Boundary Transition Properties + +**Property** The `NEWEPOCH` transition can always be invoked at the epoch boundary +(i.e. when `e = e_l + 1`). Thus, the transitions it depends on, `SNAP`, `POOLREAP`, `NEWPP`, +and `EPOCH`, can always be invoked as well. Note that when no blocks are produced, +the `CHAIN` rule is blocked and `NEWEPOCH` never fires. + +Transitions `SNAP`, `POOLREAP`, and `EPOCH` have no preconditions in the +antecedents of their rules. `NEWPP` has two associated rules, and the disjunction of the +preconditions in these rules is a tautology. We justify +the non-blocking of these rules by this reasoning. + # Deposits Properties **Property** @@ -222,23 +243,23 @@ The sum of stake in the stake snapshots is always at most forty-five billion ADA **Property** The following delegation mappings always has the same size: -`stdelegs`, `rewards`, and `ptrs`. -Moreover, the key set of `stdelegs` is the same +`stkCreds`, `rewards`, and `ptrs`. +Moreover, the key set of `stkCreds` is the same as the range of `ptrs`, which also corresponds one-one with the reward addresses -in `rewards`. Finally, the key set of `delegations` is a subset of that of `stdelegs`. +in `rewards`. Finally, the key set of `delegations` is a subset of that of `stkCreds`. **Property** If all stake keys and pools deregister, then, assuming that no one registers anything, by epoch `e+1`, where `e` is the max epoch in the stake pool retirement mapping, the delegation state will be nearly empty. More precisely, -the mappings `stDelegs`, `rewards`, `delegations`, `ptrs`, `stpools`, `poolParams`, +the mappings `stkCreds`, `rewards`, `delegations`, `ptrs`, `stpools`, `poolParams`, and `retiring` are all the empty map. (The map `cs` will have size seven, for the genesis keys.) # Genesis Node Property **Property** -The size of the genesis delegation mapping `dms` is always num-genesis. +The size of the genesis delegation mapping `genDelegs` is always num-genesis. Note that the value num-genesis can be given as the size of the mapping inherited from Byron. @@ -263,6 +284,10 @@ At the start of each epoch, the reward update is set to NOTHING. Moreover, the reward update will change exactly once during the epoch, to a non-NOTHING value. +**Property** +All members of stake pools that did not meet their pledges will receive zero +rewards for the epoch. + # Block Header Properties **Consistency Property** @@ -300,13 +325,13 @@ What are acceptable values for various system protocol parameters? The following are examples of things that should be part of some overview document -(1) potentially, multiple slot leaders may be elected for a particular slot (forming a slot leader set); +(1) potentially, multiple slot leaders may be elected for a particular slot (forming a slot leader set); -(2) frequently, slots will have no leaders assigned to them; and +(2) frequently, slots will have no leaders assigned to them; and (3) a priori, only a slot leader is aware that it is indeed a leader for a given slot; this assignment is unknown to all the other stakeholders—including other slot leaders of the same slot—until the other stakeholders receive a valid block from this slot leader. - + **Independent aggregation property (Property 2)** @@ -426,11 +451,8 @@ _These look like ways to drive test case generation_ #Multi-signature properties **Sufficient Signatures are Provided to authorise Multi-Signature Transactions** - + Outputs of transactions that require multiple signatures will be "locked" against use until at least the required number of signatures is provided. _This should come by construction from the rules in the multi-sig spec._ - - - diff --git a/shelley/chain-and-ledger/formal-spec/chain.tex b/shelley/chain-and-ledger/formal-spec/chain.tex index 871dc306c9d..7d00da8ed66 100644 --- a/shelley/chain-and-ledger/formal-spec/chain.tex +++ b/shelley/chain-and-ledger/formal-spec/chain.tex @@ -4,7 +4,6 @@ \section{Blockchain layer} \newcommand{\Proof}{\type{Proof}} \newcommand{\Seedl}{\mathsf{Seed}_\ell} \newcommand{\Seede}{\mathsf{Seed}_\eta} -\newcommand{\StartRewards}{\ensuremath{\mathsf{StartRewards}}} \newcommand{\activeSlotCoeff}[1]{\fun{activeSlotCoeff}~ \var{#1}} \newcommand{\slotToSeed}[1]{\fun{slotToSeed}~ \var{#1}} @@ -107,8 +106,6 @@ \subsection{Verifiable Random Functions (VRF)} & 0_{seed} \in \Seed & \text{neutral seed element} \\ & \Seedl \in \Seed & \text{leader seed constant} \\ & \Seede \in \Seed & \text{nonce seed constant}\\ - & \SlotsPrior \in \Duration & \tau\text{ in \cite{ouroboros_praos}}\\ - & \StartRewards \in \Duration & \text{duration to start reward calculations}\\ \end{align*} \caption{VRF definitions} @@ -640,7 +637,7 @@ \subsection{Reward Update Transition} \subsection{Block Header Transition} \label{sec:block-header-trans} -The Block Header Transition checks a couple sizes and performs some chain level upkeep. +The Block Header Transition checks a couple of sizes and performs some chain level upkeep. The environment consists of a candidate nonce and a set of genesis keys, and the state is the epoch specific state necessary for the $\mathsf{NEWEPOCH}$ transition. @@ -779,8 +776,8 @@ \subsection{Operational Certificate Transition} \begin{itemize} \item The KES period start \var{c_0} is greater than or equal to the KES period of - the slot of the block header body and less than 90 KES periods after \var{c_0}. - The value of 90 KES periods is the agreed-upon lifetime of an operational certificate, + the slot of the block header body and less than $\MaxKESEvo$-many KES periods after \var{c_0}. + The value of $\MaxKESEvo$ is the agreed-upon lifetime of an operational certificate, see \cite{delegation_design}. \item \var{hk} exists as key in the mapping of certificate issues numbers to a KES period \var{m} and that period is less than or equal to \var{n}. @@ -808,7 +805,7 @@ \subsection{Operational Certificate Transition} & t \leteq \kesPeriod{s} - c_0 \\~\\ - c_0 \leq \kesPeriod{s} < c_0 + 90 + c_0 \leq \kesPeriod{s} < c_0 + \MaxKESEvo \\ \var{hk}\mapsto m\in\var{cs} & @@ -833,7 +830,7 @@ \subsection{Operational Certificate Transition} \item If the KES period is less than the KES period start in the certificate, there is a \emph{KESBeforeStart} failure. \item If the KES period is greater than or equal to the KES period end (start + - 90) in the certificate, there is a \emph{KESAfterEnd} failure. + $\MaxKESEvo$) in the certificate, there is a \emph{KESAfterEnd} failure. \item If the period counter in the original key hash counter mapping is larger than the period number in the certificate, there is a \emph{KESPeriodWrong} failure. @@ -911,7 +908,7 @@ \subsection{Overlay Schedule} responsible for producing the block. \item The epoch nonce $\eta_0$. \item The stake pool stake distribution $\var{pd}$. - \item The mapping $\var{dms}$ of genesis keys to their cold keys. + \item The mapping $\var{genDelegs}$ of genesis keys to their cold keys. \end{itemize} The states for this transition consist only of the mapping of certificate issue numbers. @@ -946,7 +943,7 @@ \subsection{Overlay Schedule} \var{osched} & \Slot\mapsto\KeyHashGen^? & \text{OBFT overlay schedule} \\ \eta_0 & \Seed & \text{epoch nonce} \\ \var{pd} & \PoolDistr & \text{pool stake distribution} \\ - \var{dms} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ + \var{genDelegs} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ \end{array} \right) \end{equation*} @@ -973,7 +970,7 @@ \subsection{Overlay Schedule} \\ \bslot bhb \mapsto \var{gkh}\in\var{osched} & - \var{gkh}\mapsto\var{vkh}\in\var{dms} + \var{gkh}\mapsto\var{vkh}\in\var{genDelegs} \\~\\ { \vdash\var{cs}\trans{\hyperref[fig:rules:ocert]{ocert}}{\var{bh}}\var{cs'} @@ -985,7 +982,7 @@ \subsection{Overlay Schedule} \var{osched} \\ \eta_0 \\ \var{pd} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array}} \vdash \var{cs} @@ -1015,7 +1012,7 @@ \subsection{Overlay Schedule} \var{osched} \\ \eta_0 \\ \var{pd} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array}} \vdash \var{cs} @@ -1362,7 +1359,7 @@ \subsection{Chain Transition} \emph{Chain Transition Helper Functions} \begin{align*} & \fun{getGKeys} \in \NewEpochState \to \powerset{\KeyHashGen} \\ - & \fun{getGKeys}~\var{nes} = \dom{dms} \\ + & \fun{getGKeys}~\var{nes} = \dom{genDelegs} \\ & \begin{array}{lr@{~=~}l} \where @@ -1372,7 +1369,7 @@ \subsection{Chain Transition} & (\wcard,~\wcard,~\var{ls},~\wcard) & \var{es} \\ - & (\wcard,~((\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{dms}),~\wcard)) + & (\wcard,~((\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{genDelegs}),~\wcard)) & \var{ls} \end{array} \end{align*} @@ -1423,7 +1420,7 @@ \subsection{Chain Transition} \leteq\var{nes'} \\ (\var{acnt},~\wcard,\var{ls},~\var{pp})\leteq\var{es}\\ ( \wcard, - ( (\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{dms}),~ + ( (\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{genDelegs}),~ (\wcard,~\wcard,~\wcard,~\var{cs})))\leteq\var{ls}\\ (\wcard, reserves) \leteq \var{acnt}\\ { @@ -1433,7 +1430,7 @@ \subsection{Chain Transition} \var{osched} \\ \eta_0 \\ \var{pd} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array}\\ \var{s_{now}} \\ \end{array}} @@ -1507,6 +1504,8 @@ \subsection{Byron to Shelley Transition} The Byron ledger state $\CEState$ is defined in \cite{byron_chain_spec}. Figure~\ref{fig:functions:to-shelley} defines a function $\fun{toShelley}$ which takes the Byron ledger state and creates the Shelley ledger state. +Note that we use the hash of the final Byron header as the first evolving and +candidate nonces for Shelley. %% %% Figure - Byron to Shelley State Transition diff --git a/shelley/chain-and-ledger/formal-spec/crypto-primitives.tex b/shelley/chain-and-ledger/formal-spec/crypto-primitives.tex index 7d4ceb5a6b6..54c1261e151 100644 --- a/shelley/chain-and-ledger/formal-spec/crypto-primitives.tex +++ b/shelley/chain-and-ledger/formal-spec/crypto-primitives.tex @@ -17,10 +17,6 @@ \section{Cryptographic primitives} some data signed with a (private) key is only correct whenever we can verify it using the corresponding public key. -Besides basic cryptographic abstractions, we also make use of some abstract -data storage properties in this document in order to build necessary definitions -and make judgement calls about them. - Abstract data types in this paper are essentially placeholders with names indicating the data types they are meant to represent in an implementation. Derived types are made up of data structures (i.e.~products, lists, finite @@ -97,8 +93,8 @@ \section{Cryptographic primitives} corresponding private key evolves incrementally. For this reason, KES verification keys are indexed by integers representing the step in the key's evolution. This evolution step parameter is also an additional parameter needed -for the signing (denoted by $\signEv$) and verification -(denoted by $\verifyEv$) functions. +for the signing (denoted by $\fun{signEv}$) and verification +(denoted by $\fun{verifyEv}$) functions. Since the private key evolves incrementally in a KES scheme, the ledger rules require the pool operators to evolve their keys once per KES period-slots. diff --git a/shelley/chain-and-ledger/formal-spec/delegation.tex b/shelley/chain-and-ledger/formal-spec/delegation.tex index c5b972c4f6f..c8ab4136bb2 100644 --- a/shelley/chain-and-ledger/formal-spec/delegation.tex +++ b/shelley/chain-and-ledger/formal-spec/delegation.tex @@ -54,7 +54,7 @@ \subsection{Delegation Definitions} \end{itemize} The following derived types are introduced: \begin{itemize} -\item $\type{StakeDelegs}$ represents registered stake delegations and is +\item $\type{StakeCreds}$ represents registered stake delegations and is represented by a finite map from stake credentials to slot when it was registered. \item$\type{StakePools}$ represents registered stake pools @@ -120,18 +120,22 @@ \subsection{Delegation Definitions} % \emph{Derived types} \begin{equation*} - \begin{array}{l@{\qquad=\qquad}lr} - \StakeDelegs + \begin{array}{lclr} + \StakeCreds + & ~=~ & \Credential \mapsto \Slot & \text{registered stake credential} \\ % \StakePools + & ~=~ & \KeyHash \mapsto \Slot & \text{registered stake pools} \\ % \PoolParam - & \powerset{\KeyHash} \times \Coin \times \unitInterval \times \Coin \times \AddrRWD + & ~=~ + & \powerset{\KeyHash} \times \Coin \times \unitInterval \times \Coin & \text{stake pool parameters} \\ + & & \qquad \times \AddrRWD \times \KeyHash_{vrf} \end{array} \end{equation*} % @@ -139,7 +143,7 @@ \subsection{Delegation Definitions} % \begin{equation*} \begin{array}{r@{~\in~}lr} - \cwitness{} & \DCert\setminus\DCertMir \to \StakeDelegs & \text{certificate witness} \\ + \cwitness{} & \DCert\setminus\DCertMir \to \StakeCreds & \text{certificate witness} \\ \fun{dpool} & \DCertDeleg \to \KeyHash & \text{pool being delegated to} \\ @@ -149,7 +153,7 @@ \subsection{Delegation Definitions} \fun{retire} & \DCertRetirePool \to \Epoch & \text{epoch of pool retirement} \\ - \fun{genDel} & \DCertGen \to (\VKeyGen,~\VKey) + \fun{genesisDeleg} & \DCertGen \to (\VKeyGen,~\VKey) & \text{genesis delegation} \\ \fun{moveRewards} & \DCertMir \to (\KeyHash \mapsto \Coin) @@ -198,7 +202,7 @@ \subsection{Delegation Transitions} \begin{itemize} \item $\DState$ keeps track of the delegation state, consisting of: \begin{itemize} - \item $\var{stdelegs}$ tracks the registered stake credentials. It consists + \item $\var{stkCreds}$ tracks the registered stake credentials. It consists of a finite mapping from hashkeys to the slot of the registration. \item $\var{rewards}$ stores the rewards accumulated by stake credentials. These are represented by a finite map from reward addresses to the @@ -208,11 +212,11 @@ \subsection{Delegation Transitions} \item $\var{ptrs}$ maps stake credentials to the position of the registration certificate in the blockchain. This is needed to lookup the stake hashkey of a pointer address. - \item $\var{fdms}$ are the future genesis keys delegations. This variable + \item $\var{fGenDelegs}$ are the future genesis keys delegations. This variable is needed because genesis keys can only update their delegation with a delay of $\SlotsPrior$ slots after submitting the certificate (this is necessary for header validation, see Section \ref{sec:chain}) - \item $\var{dms}$ maps genesis key hashes to hashes of the cold key + \item $\var{genDelegs}$ maps genesis key hashes to hashes of the cold key delegates. \item $\var{i_{rwd}}$ stored the map of stake credentials to $\Coin$ values for moving instantaneous rewards at the epoch boundary. @@ -252,7 +256,7 @@ \subsection{Delegation Transitions} \begin{array}{r@{~\in~}l@{\qquad=\qquad}lr} \var{stakeCred} & \StakeCredential & (\KeyHash_{stake} \uniondistinct \HashScr) \\ - \var{stakeDelegator} & \StakeDelegs & \StakeCredential \mapsto \Slot \\ + \var{stakeDelegator} & \StakeCreds & \StakeCredential \mapsto \Slot \\ \end{array} \end{equation*} % @@ -262,12 +266,12 @@ \subsection{Delegation Transitions} \begin{array}{l} \DState = \left(\begin{array}{r@{~\in~}lr} - \var{stDelegs} & \StakeDelegs & \text{registered stake delegators}\\ + \var{stkCreds} & \StakeCreds & \text{registered stake delegators}\\ \var{rewards} & \AddrRWD \mapsto \Coin & \text{rewards}\\ \var{delegations} & \StakeCredential \mapsto \KeyHash_{pool} & \text{delegations}\\ \var{ptrs} & \Ptr \mapsto \KeyHash & \text{pointer to hashkey}\\ - \var{fdms} & (\Slot\times\KeyHashGen) \mapsto \KeyHash & \text{future genesis key delegations}\\ - \var{dms} & \KeyHashGen \mapsto \KeyHash & \text{genesis key delegations}\\ + \var{fGenDelegs} & (\Slot\times\KeyHashGen) \mapsto \KeyHash & \text{future genesis key delegations}\\ + \var{genDelegs} & \KeyHashGen \mapsto \KeyHash & \text{genesis key delegations}\\ \var{i_{rwd}} & \KeyHash \mapsto \Coin & \text{instantaneous rewards}\\ \end{array} \right) @@ -372,7 +376,7 @@ \subsection{Delegation Rules} \end{itemize} \item Genesis key delegation is handled by \cref{eq:deleg-gen}. - There is a precondition that the genesis key is already in the mapping $\var{dms}$. + There is a precondition that the genesis key is already in the mapping $\var{genDelegs}$. Genesis delegation causes the following state transformation: \begin{itemize} \item The future genesis delegation relation is updated with the new delegate @@ -395,7 +399,7 @@ \subsection{Delegation Rules} \begin{equation}\label{eq:deleg-reg} \inference[Deleg-Reg] { - \var{c}\in\DCertRegKey & hk \leteq \cwitness{c} & hk \notin \dom \var{stdelegs} + \var{c}\in\DCertRegKey & hk \leteq \cwitness{c} & hk \notin \dom \var{stkCreds} } { \begin{array}{r} @@ -406,24 +410,24 @@ \subsection{Delegation Rules} \vdash \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \trans{deleg}{\var{c}} \left( \begin{array}{rcl} - \varUpdate{\var{stdelegs}} & \varUpdate{\union} & \varUpdate{\{\var{hk} \mapsto slot\}} \\ + \varUpdate{\var{stkCreds}} & \varUpdate{\union} & \varUpdate{\{\var{hk} \mapsto slot\}} \\ \varUpdate{\var{rewards}} & \varUpdate{\union} & \varUpdate{\{\addrRw \var{hk} \mapsto 0\}}\\ \var{delegations} \\ \varUpdate{\var{ptrs}} & \varUpdate{\union} & \varUpdate{\{ptr \mapsto \var{hk}\}} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) @@ -434,7 +438,7 @@ \subsection{Delegation Rules} \inference[Deleg-Dereg] { \var{c}\in \DCertDeRegKey & hk \leteq \cwitness{c} \\ - hk \in \dom \var{stdelegs} & \addrRw \var{hk} \mapsto 0 \in \var{rewards} + hk \in \dom \var{stkCreds} & \addrRw \var{hk} \mapsto 0 \in \var{rewards} } { \begin{array}{r} @@ -445,24 +449,24 @@ \subsection{Delegation Rules} \vdash \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \trans{deleg}{\var{c}} \left( \begin{array}{rcl} - \varUpdate{\{\var{hk}\}} & \varUpdate{\subtractdom} & \varUpdate{\var{stdelegs}} \\ + \varUpdate{\{\var{hk}\}} & \varUpdate{\subtractdom} & \varUpdate{\var{stkCreds}} \\ \varUpdate{\{\addrRw \var{hk}\}} & \varUpdate{\subtractdom} & \varUpdate{\var{rewards}} \\ \varUpdate{\{\var{hk}\}} & \varUpdate{\subtractdom} & \varUpdate{\var{delegations}} \\ \varUpdate{\var{ptrs}} & \varUpdate{\subtractrange} & \varUpdate{\{\var{hk}\}} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) @@ -472,7 +476,7 @@ \subsection{Delegation Rules} \begin{equation}\label{eq:deleg-deleg} \inference[Deleg-Deleg] { - \var{c}\in \DCertDeleg & hk \leteq \cwitness{c} & hk \in \dom \var{stdelegs} + \var{c}\in \DCertDeleg & hk \leteq \cwitness{c} & hk \in \dom \var{stkCreds} } { \begin{array}{r} @@ -483,25 +487,25 @@ \subsection{Delegation Rules} \vdash \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \trans{deleg}{c} \left( \begin{array}{rcl} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \varUpdate{\var{delegations}} & \varUpdate{\unionoverrideRight} & \varUpdate{\{\var{hk} \mapsto \dpool c\}} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) @@ -512,14 +516,14 @@ \subsection{Delegation Rules} \inference[Deleg-Gen] { \var{c}\in \DCertGen - & (\var{gkey},~\var{vk})\leteq\fun{genDel}~{c} + & (\var{gkey},~\var{vk})\leteq\fun{genesisDeleg}~{c} \\ \var{gkh} \leteq \hashKey{gkey} & \var{vkh} \leteq \hashKey{vk} \\ s'\leteq\var{slot}+\SlotsPrior - & \var{gkh}\in\dom{dms} - & \var{vk}\notin\range{dms} + & \var{gkh}\in\dom{genDelegs} + & \var{vk}\notin\range{genDelegs} } { \begin{array}{r} @@ -530,25 +534,25 @@ \subsection{Delegation Rules} \vdash \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \trans{deleg}{c} \left( \begin{array}{rcl} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \varUpdate{\var{fdms}} & \varUpdate{\unionoverrideRight} + \varUpdate{\var{fGenDelegs}} & \varUpdate{\unionoverrideRight} & \varUpdate{\{(\var{s'},~\var{gkh}) \mapsto \var{vkh}\}} \\ - \var{dms} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) @@ -578,24 +582,24 @@ \subsection{Delegation Rules} \vdash \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \trans{deleg}{c} \left( \begin{array}{rcl} - \var{stdelegs}\\ + \var{stkCreds}\\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms}\\ - \var{dms} \\ + \var{fGenDelegs}\\ + \var{genDelegs} \\ \varUpdate{\var{i_{rwd}}} & \varUpdate{\unionoverrideRight} & \varUpdate{\fun{moveRewards}~\var{c}} \end{array} @@ -606,7 +610,7 @@ \subsection{Delegation Rules} \label{fig:dcert-mir} \end{figure} -The DELEG rule has six predicate failures: +The DELEG rule has seven possible predicate failures: \begin{itemize} \item In the case of a key registration certificate, if the staking credential is already registered, there is a a \emph{StakeKeyAlreadyRegistered} failure. @@ -622,6 +626,8 @@ \subsection{Delegation Rules} \item In the case of a genesis key delegation certificate, if the delegate key is in the range of the genesis delegation mapping, there is a \emph{DuplicateGenesisDelegate} failure. +\item In the case of insufficient reserves to pay the instantaneous rewards, + there is a \emph{InsufficientForInstantaneousRewards} failure. \end{itemize} \clearpage @@ -863,7 +869,7 @@ \subsection{Delegation and Pool Combined Rules} \emph{Delegation and Pool Combined Rules} \begin{equation} \label{eq:delpl-d} - \inference[Delpl-Del] + \inference[Delpl-Deleg] { & { @@ -1021,12 +1027,12 @@ \subsection{Delegation and Pool Combined Rules} \begin{array}{c} \left( \begin{array}{r} - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \\~\\ @@ -1045,12 +1051,12 @@ \subsection{Delegation and Pool Combined Rules} \begin{array}{c} \left( \begin{array}{c} - \var{stdelegs} \\ + \var{stkCreds} \\ \varUpdate{\var{rewards'}} \\ \var{delegations} \\ \var{ptrs} \\ - \var{fdms} \\ - \var{dms} \\ + \var{fGenDelegs} \\ + \var{genDelegs} \\ \var{i_{rwd}} \end{array} \right) \\~\\ diff --git a/shelley/chain-and-ledger/formal-spec/epoch.tex b/shelley/chain-and-ledger/formal-spec/epoch.tex index d6d572f535d..180768e2f6a 100644 --- a/shelley/chain-and-ledger/formal-spec/epoch.tex +++ b/shelley/chain-and-ledger/formal-spec/epoch.tex @@ -136,9 +136,9 @@ \subsection{Helper Functions and Accounting Fields} \begin{figure}[htb] \emph{Total possible refunds} \begin{align*} - & \fun{obligation} \in \PParams \to \StakeDelegs \to \StakePools \to \Slot \to \Coin \\ - & \obligation{pp}{stdelegs}{stpools}{cslot} =\\ - & \sum\limits_{(\_ \mapsto s) \in \var{stdelegs}} + & \fun{obligation} \in \PParams \to \StakeCreds \to \StakePools \to \Slot \to \Coin \\ + & \obligation{pp}{stkCreds}{stpools}{cslot} =\\ + & \sum\limits_{(\_ \mapsto s) \in \var{stkCreds}} \refund{d_{\mathsf{val}}}{d_{\min}}{\lambda_d}{(\slotminus{cslot}{s})} + \sum\limits_{(\_ \mapsto s) \in \var{stpools}} \refund{p_{\mathsf{val}}}{p_{\min}}{\lambda_p}{(\slotminus{cslot}{s})} \\ @@ -282,7 +282,7 @@ \subsection{Stake Distribution Calculation} & \fun{stakeDistr}~{utxo}~{dstate}~{pstate} = (\dom{\var{activeDelegs}})\restrictdom\left(\fun{aggregate_{+}}~\var{stakeRelation}\right)\\ & \where \\ - & ~~~~ (\var{stdelegs},~\var{rewards},~\var{delegations},~\var{ptrs},~\wcard,~\wcard) + & ~~~~ (\var{stkCreds},~\var{rewards},~\var{delegations},~\var{ptrs},~\wcard,~\wcard) = \var{dstate} \\ & ~~~~ (\var{stpools},~\wcard,~\wcard,~\wcard,~\wcard) = \var{pstate} \\ & ~~~~ \var{stakeRelation} = \left( @@ -291,7 +291,7 @@ \subsection{Stake Distribution Calculation} \right) \cup \left(\fun{stakeCred_r}^{-1}\circ\var{rewards}\right) \\ & ~~~~ \var{activeDelegs} = - (\dom{stdelegs}) \restrictdom \var{delegations} \restrictrange (\dom{stpools}) \\ + (\dom{stkCreds}) \restrictdom \var{delegations} \restrictrange (\dom{stpools}) \\ \end{align*} \caption{Stake Distribution Function} @@ -396,11 +396,11 @@ \subsection{Snapshot Transition} { \begin{array}{r@{~\leteq~}l} (\var{utxo},~\var{deposits},~\var{fees},~\wcard) & \var{utxoSt}\\ - (\var{stdelegs},~\wcard,~\var{delegations},~\wcard,~\wcard,~\wcard) & \var{dstate}\\ + (\var{stkCreds},~\wcard,~\var{delegations},~\wcard,~\wcard,~\wcard) & \var{dstate}\\ (\var{stpools},~\var{poolParams},~\wcard,~\wcard) & \var{pstate}\\ \var{stake} & \stakeDistr{utxo}{dstate}{pstate} \\ \var{slot} & \firstSlot{e} \\ - \var{oblg} & \obligation{pp}{stdelegs}{stpools}{slot} \\ + \var{oblg} & \obligation{pp}{stkCreds}{stpools}{slot} \\ \var{decayed} & \var{deposits} - \var{oblg} \\ \end{array} } @@ -541,11 +541,11 @@ \subsection{Pool Reaping Transition} \var{treasury} \\ \var{reserves} \\ ~ \\ - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{dms} \\ + \var{genDelegs} \\ ~ \\ \var{stpools} \\ \var{poolParams} \\ @@ -566,11 +566,11 @@ \subsection{Pool Reaping Transition} \varUpdate{\var{treasury}} & \varUpdate{+} & \varUpdate{\var{unclaimed}} \\ \var{reserves} \\ ~ \\ - \var{stdelegs} \\ + \var{stkCreds} \\ \varUpdate{\var{rewards}} & \varUpdate{\unionoverridePlus} & \varUpdate{\var{refunds}} \\ \varUpdate{\var{delegations}} & \varUpdate{\subtractrange} & \varUpdate{\var{retired}} \\ \var{ptrs} \\ - \var{dms} \\ + \var{genDelegs} \\ ~ \\ \varUpdate{\var{retired}} & \varUpdate{\subtractdom} & \varUpdate{\var{stpools}} \\ \varUpdate{\var{retired}} & \varUpdate{\subtractdom} & \varUpdate{\var{poolParams}} \\ @@ -679,8 +679,8 @@ \subsection{Protocol Parameters Update Transition} \var{pp_{new}}\neq\Nothing \\~\\ {\begin{array}{rcl} \var{slot} & \leteq & \firstSlot{e} \\ - \var{oblg_{cur}} & \leteq & \obligation{pp}{stdelegs}{stpools}{slot} \\ - \var{oblg_{new}} & \leteq & \obligation{pp_{new}}{stdelegs}{stpools}{slot} \\ + \var{oblg_{cur}} & \leteq & \obligation{pp}{stkCreds}{stpools}{slot} \\ + \var{oblg_{new}} & \leteq & \obligation{pp_{new}}{stkCreds}{stpools}{slot} \\ \var{(\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{i_{rwd}})} & \leteq & \var{dstate}\\ @@ -759,8 +759,8 @@ \subsection{Protocol Parameters Update Transition} \\~\\~\\ {\begin{array}{rcl} \var{slot} & \leteq & \firstSlot{e} \\ - \var{oblg_{cur}} & \leteq & \obligation{pp}{stdelegs}{stpools}{slot} \\ - \var{oblg_{new}} & \leteq & \obligation{pp_{new}}{stdelegs}{stpools}{slot} \\ + \var{oblg_{cur}} & \leteq & \obligation{pp}{stkCreds}{stpools}{slot} \\ + \var{oblg_{new}} & \leteq & \obligation{pp_{new}}{stkCreds}{stpools}{slot} \\ \var{(\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\wcard,~\var{i_{rwd}})} & \leteq & \var{dstate}\\ @@ -1351,7 +1351,7 @@ \subsection{Reward Update Calculation} & ~~~~~~~\left( \wcard,~ \left( - \left(\var{stDelegs},~\var{rewards},~\wcard,~\wcard,~\wcard,~\wcard,~\var{i_{rwd}}\right)~ + \left(\var{stkCreds},~\var{rewards},~\wcard,~\wcard,~\wcard,~\wcard,~\var{i_{rwd}}\right)~ \wcard \right) \right) = \var{ls} \\ @@ -1375,11 +1375,12 @@ \subsection{Reward Update Calculation} \in newlyRegister \right\}\\ & ~~~~~~~\Delta d = \vert newlyRegister \vert\cdot\fun{keydeposit}~\var{pp} \\ - & ~~~~~~~\Delta r = \floor*{\min(1,\eta) \cdot (\fun{rho}~{pp}) \cdot - \var{reserves'}} + rewards_{mir} + & ~~~~~~~\Delta r_{l} = \floor*{\min(1,\eta) \cdot (\fun{rho}~{pp}) \cdot + \var{reserves'}} \\ + & ~~~~~~~\Delta r = \Delta r_{l} + rewards_{mir}\\ & ~~~~~~~\eta = \frac{blocksMade}{\SlotsPerEpoch \cdot \fun{activeSlotCoeff}~{pp}} \\ - & ~~~~~~~\var{rewardPot} = \var{feeSS} + \Delta r \\ + & ~~~~~~~\var{rewardPot} = \var{feeSS} + \Delta r_{l} \\ & ~~~~~~~\Delta t_1 = \floor*{(\fun{tau}~{pp}) \cdot \var{rewardPot}} \\ & ~~~~~~~\var{R} = \var{rewardPot} - \Delta t_1 \\ & ~~~~~~~\var{rs} @@ -1414,11 +1415,11 @@ \subsection{Reward Update Calculation} \var{treasury} \\ \var{reserves} \\ ~ \\ - \var{stdelegs} \\ + \var{stkCreds} \\ \var{rewards} \\ \var{delegations} \\ \var{ptrs} \\ - \var{dms} \\ + \var{genDelegs} \\ \var{i_{rwd}} \\~ \\ \var{stpools} \\ @@ -1438,11 +1439,11 @@ \subsection{Reward Update Calculation} \varUpdate{\var{treasury} + \Delta t}\\ \varUpdate{\var{reserves} + \Delta r}\\ ~ \\ - \varUpdate{\var{stdelegs}\unionoverrideLeft \var{update_{delegs}}} \\ + \varUpdate{\var{stkCreds}\unionoverrideLeft \var{update_{delegs}}} \\ \varUpdate{(\var{rewards}\unionoverridePlus\var{rs})\unionoverridePlus\var{update_{rwd}}} \\ \var{delegations} \\ \var{ptrs} \\ - \var{dms} \\ + \var{genDelegs} \\ \varUpdate{\emptyset} \\~ \\ \var{stpools} \\ diff --git a/shelley/chain-and-ledger/formal-spec/incentives.tex b/shelley/chain-and-ledger/formal-spec/incentives.tex index 9998e989a64..980bda28cb9 100644 --- a/shelley/chain-and-ledger/formal-spec/incentives.tex +++ b/shelley/chain-and-ledger/formal-spec/incentives.tex @@ -1031,7 +1031,7 @@ \subsubsection*{Calculated Rewards} owners and delegators to this StakePool would receive a net reward that was equivalent to 8.33\% per year (the ``staking yield''), representing a 17\% better return than with the simplified scheme. The final rows calculate the \emph{non-myopic} rewards (i.e. long-term rewards that ensure -a stable and well-functioning system). As described in~\cite{SL-D1}, these values will be used to guide stakeholder behaviour +a stable and well-functioning system). As described in~\cite{delegation_design}, these values will be used to guide stakeholder behaviour through a ranking system that will encourage convergence to the $k$ best-performing pools. For this pool, which is \emph{saturated}, the non-myopic rewards are identical to the \emph{optimal rewards}. \khcomment{Is this always the case?} diff --git a/shelley/chain-and-ledger/formal-spec/ledger-spec.tex b/shelley/chain-and-ledger/formal-spec/ledger-spec.tex index 672ffb0aa9c..78448a272e8 100644 --- a/shelley/chain-and-ledger/formal-spec/ledger-spec.tex +++ b/shelley/chain-and-ledger/formal-spec/ledger-spec.tex @@ -58,7 +58,7 @@ \newcommand{\Nothing}{\ensuremath{\Diamond}} \newcommand{\N}{\ensuremath{\mathbb{N}}} \newcommand{\Bool}{\type{Bool}} -\newcommand{\Npos}{\ensuremath{\mathbb{N}^{+}}} +\newcommand{\Npos}{\ensuremath{\mathbb{N}^{>0}}} \newcommand{\Z}{\ensuremath{\mathbb{Z}}} \newcommand{\R}{\ensuremath{\mathbb{R}}} \newcommand{\Rnn}{\ensuremath{\mathbb{R}^{\geq 0}}} @@ -76,10 +76,12 @@ \newcommand{\SlotsPrior}{\ensuremath{\mathsf{SlotsPrior}}} \newcommand{\SlotsPerEpoch}{\mathsf{SlotsPerEpoch}} \newcommand{\SlotsPerKESPeriod}{\mathsf{SlotsPerKESPeriod}} -\newcommand{\SlotsStabilityParam}{\fun{k}} +\newcommand{\StartRewards}{\ensuremath{\mathsf{StartRewards}}} +\newcommand{\MaxKESEvo}{\ensuremath{\mathsf{MaxKESEvo}}} +\newcommand{\Quorum}{\ensuremath{\mathsf{Quorum}}} \newcommand{\Duration}{\type{Duration}} \newcommand{\StakePools}{\type{StakePools}} -\newcommand{\StakeDeleg}{\type{StakeDeleg}} +\newcommand{\StakeCreds}{\type{StakeCreds}} \newcommand{\Seed}{\type{Seed}} \newcommand{\seedOp}{\star} \newcommand{\Ppm}{\type{Ppm}} @@ -129,7 +131,6 @@ % multi-signature \newcommand{\StakeCredential}{\type{Credential}_{stake}} -\newcommand{\StakeDelegs}{\type{StakeDelegs}} \newcommand{\txwitsVKey}[1]{\fun{txwitsVKey}~\var{#1}} \newcommand{\txwitsScript}[1]{\fun{txwitsScript}~\var{#1}} diff --git a/shelley/chain-and-ledger/formal-spec/ledger.tex b/shelley/chain-and-ledger/formal-spec/ledger.tex index 1a7deaf737b..daaee5193b6 100644 --- a/shelley/chain-and-ledger/formal-spec/ledger.tex +++ b/shelley/chain-and-ledger/formal-spec/ledger.tex @@ -76,16 +76,16 @@ \section{Ledger State Transition} \fun{txcerts}~\var{tx}} dpstate' \\~\\ (\var{dstate}, \var{pstate}) \leteq \var{dpstate} \\ - (\var{stdelegs}, \_, \_, \_, \_, \var{dms}) \leteq \var{dstate} \\ + (\var{stkCreds}, \_, \_, \_, \_, \var{genDelegs}) \leteq \var{dstate} \\ (\var{stpools}, \_, \_, \_) \leteq \var{pstate} \\ \\~\\ { \begin{array}{c} \var{slot} \\ \var{pp} \\ - \var{stdelegs} \\ + \var{stkCreds} \\ \var{stpools} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array} } \vdash \var{utxoSt} \trans{\hyperref[fig:rules:utxow-shelley]{utxow}}{tx} \var{utxoSt'} @@ -126,7 +126,7 @@ \section{Ledger State Transition} Note that it is better to handle this logic here than in the $\mathsf{AVUP}$ transiton, because here it will happen even if the block contains no transactions. Similarly, the genesis key delegation mapping is updated according to the future delegation -mapping. For each genesis key, we adopt the most recent delegation in $\var{fdms}$ +mapping. For each genesis key, we adopt the most recent delegation in $\var{fGenDelegs}$ that is past the current slot, and any future genesis key delegations past the current slot is removed. @@ -152,7 +152,7 @@ \section{Ledger State Transition} \\ (\var{pup},~\var{aup},~\var{favs},~\var{avs}) \leteq\var{us} \\ - (\var{stkeys},~\var{rewards},~\var{delegations}, ~\var{ptrs},~\var{fdms},~\var{dms}) + (\var{stkeys},~\var{rewards},~\var{delegations}, ~\var{ptrs},~\var{fGenDelegs},~\var{genDelegs}) \leteq\var{ds} \\ (\var{stpools},~\var{poolParams},~\var{retiring},~\var{cs})\leteq\var{ps} @@ -166,11 +166,11 @@ \section{Ledger State Transition} \\~\\ \var{curr}\leteq \{ - (\var{s},~\var{gkh})\mapsto\var{vkh}\in\var{fdms} + (\var{s},~\var{gkh})\mapsto\var{vkh}\in\var{fGenDelegs} ~\mid~ \var{s}\leq\var{slot} \}\\ - \var{dms'}\leteq + \var{genDelegs'}\leteq \left\{ \var{gkh}\mapsto\var{vkh} ~\mathrel{\Bigg|}~ @@ -186,12 +186,12 @@ \section{Ledger State Transition} \\ \var{ds'}\leteq (\var{stkeys},~\var{rewards},~\var{delegations},~\var{ptrs}, - ~\var{fdms}\setminus\var{curr},~\var{dms}\unionoverrideRight\var{dms'}) + ~\var{fGenDelegs}\setminus\var{curr},~\var{genDelegs}\unionoverrideRight\var{genDelegs'}) \\ - \var{oldGenDelegs}\leteq\range((\dom\var{dms'})\restrictdom\var{dms}) + \var{oldGenDelegs}\leteq\range((\dom\var{genDelegs'})\restrictdom\var{genDelegs}) \\ - \var{cs'}\leteq(\var{oldGenDelegs}\subtractdom\var{oldGenDelegs})\unionoverrideRight - \{\var{hk}\mapsto 0~\mid~\var{hk}\in\range{dms'}\} + \var{cs'}\leteq(\var{oldGenDelegs}\subtractdom\var{cs})\unionoverrideRight + \{\var{hk}\mapsto 0~\mid~\var{hk}\in\range{genDelegs'}\} \\ \var{ps'}\leteq(\var{stpools},~\var{poolParams},~\var{retiring},~\var{cs'}) \\ diff --git a/shelley/chain-and-ledger/formal-spec/multi-sig.tex b/shelley/chain-and-ledger/formal-spec/multi-sig.tex index c560ff433d4..5f05cac5c46 100644 --- a/shelley/chain-and-ledger/formal-spec/multi-sig.tex +++ b/shelley/chain-and-ledger/formal-spec/multi-sig.tex @@ -81,7 +81,7 @@ \newcommand{\SlotsPerKESPeriod}{\mathsf{SlotsPerKESPeriod}} \newcommand{\Duration}{\type{Duration}} \newcommand{\StakePools}{\type{StakePools}} -\newcommand{\StakeDelegs}{\type{StakeDelegs}} +\newcommand{\StakeCreds}{\type{StakeCreds}} \newcommand{\StakeObject}{\type{StakeCredential}} \newcommand{\DCert}{\type{DCert}} @@ -538,7 +538,7 @@ \subsection{Delegation Specific Changes} Staking using multiple signatures requires a change to the type of staking reference from just a hashed key to either a hashed key or a hashed script. This is -reflected in the type of $\StakeDelegs$ (which replaces the previous +reflected in the type of $\StakeCreds$ (which replaces the previous $\type{StakeKeys}$ type) and the new $\StakeObject$ type, % (which describes either a key or a script used for staking), as shown in Figure~\ref{fig:delegation-state-type}. @@ -549,7 +549,7 @@ \subsection{Delegation Specific Changes} \begin{array}{r@{~\in~}l@{\qquad=\qquad}lr} \var{stakeCred} & \StakeObject & (\KeyHash_{stake} \uniondistinct \HashScr) \\ - \var{stakeDelegator} & \StakeDelegs & \StakeObject \mapsto \Slot \\ + \var{regCreds} & \StakeCreds & \StakeObject \mapsto \Slot \\ \end{array} \end{equation*} % @@ -559,12 +559,12 @@ \subsection{Delegation Specific Changes} \begin{array}{l} \DState = \left(\begin{array}{r@{~\in~}lr} - \var{stDelegs} & \StakeDelegs & \text{registered stake delegators}\\ + \var{stkCreds} & \StakeCreds & \text{registered stake delegators}\\ \var{rewards} & \AddrRWD \mapsto \Coin & \text{rewards}\\ \var{delegations} & \StakeObject \mapsto \KeyHash_{pool} & \text{delegations}\\ \var{ptrs} & \Ptr \mapsto \StakeObject & \text{pointer to staking reference}\\ - \var{fdms} & (\Slot\times\VKeyGen) \mapsto \VKey & \text{future genesis key delegations}\\ - \var{dms} & \VKeyGen \mapsto \VKey & \text{genesis key delegations}\\ + \var{fGenDelegs} & (\Slot\times\VKeyGen) \mapsto \VKey & \text{future genesis key delegations}\\ + \var{genDelegs} & \VKeyGen \mapsto \VKey & \text{genesis key delegations}\\ \end{array}\right) \end{array} \end{equation*} @@ -573,7 +573,7 @@ \subsection{Delegation Specific Changes} % \begin{equation*} \begin{array}{r@{~\in~}lr} - \cwitness{} & \DCert \to \StakeDelegs & \text{certificate witness} + \cwitness{} & \DCert \to \StakeCreds & \text{certificate witness} \end{array} \end{equation*} \caption{Delegation State type} diff --git a/shelley/chain-and-ledger/formal-spec/properties.tex b/shelley/chain-and-ledger/formal-spec/properties.tex index 0a26433554c..bef8898a377 100644 --- a/shelley/chain-and-ledger/formal-spec/properties.tex +++ b/shelley/chain-and-ledger/formal-spec/properties.tex @@ -77,7 +77,7 @@ \subsection{Ledger Properties} \forall \var{l}, \var{l'} \in \LState: \applyFun{validLedgerstate}{l}, l=(u,\wcard,\wcard,\wcard), l' = (u',\wcard,\wcard,\wcard)\\ \implies \forall \var{tx} \in \Tx, lenv \in\LEnv, lenv \vdash\var{u} \trans{utxow}{tx} \var{u'} \\ - \implies \applyFun{destroyed}{pc~utxo~stDelegs~rewards~tx} = + \implies \applyFun{destroyed}{pc~utxo~stkCreds~rewards~tx} = \applyFun{created}{pc~stPools~tx} \end{multline*} \label{prop:ledger-properties-1} @@ -198,8 +198,8 @@ \subsection{Ledger State Properties for Delegation Transitions} \begin{align*} \fun{getStDelegs} & \in & \DState \to \powerset \Credential \\ \fun{getStDelegs} & \coloneqq & - ((\var{stDelegs}, \wcard, - \wcard,\wcard,\wcard,\wcard) \to \var{stDelegs} \\ + ((\var{stkCreds}, \wcard, + \wcard,\wcard,\wcard,\wcard) \to \var{stkCreds} \\ &&\\ \fun{getRewards} & \in & \DState \to (\AddrRWD \mapsto \Coin) \\ \fun{getRewards} & \coloneqq & (\wcard, \var{rewards}, @@ -287,7 +287,7 @@ \subsection{Ledger State Properties for Delegation Transitions} \begin{multline*} \forall \var{l}, \var{l'} \in \LState: \applyFun{validLedgerstate}{l},\\ \implies \forall \Gamma \in \seqof{\Tx}, env \in (\Slot \times \PParams), \\ - env \vdash\var{l} \trans{ledgers}{\Gamma} \var{l'} \implies |dms| = 7 + env \vdash\var{l} \trans{ledgers}{\Gamma} \var{l'} \implies |genDelegs| = 7 \end{multline*} \end{property} diff --git a/shelley/chain-and-ledger/formal-spec/protocol-parameters.tex b/shelley/chain-and-ledger/formal-spec/protocol-parameters.tex index d984f04046f..dfccd673c9b 100644 --- a/shelley/chain-and-ledger/formal-spec/protocol-parameters.tex +++ b/shelley/chain-and-ledger/formal-spec/protocol-parameters.tex @@ -12,11 +12,20 @@ \section{Protocol Parameters} Negative values will not be allowed in UTxO outputs or reward accounts, and $\Z$ is only chosen over $\N$ for its additive inverses. -Two global constants are defined, $\SlotsPerEpoch$ and $\SlotsPerKESPeriod$, -representing the number of slots in an epoch/KES period (for a brief explanation +Six global constants are defined. +As global constants, these values can only be changed by updating the software. +The constants $\SlotsPerEpoch$ and $\SlotsPerKESPeriod$ +represent the number of slots in an epoch/KES period (for a brief explanation of a KES period, see Section \ref{sec:crypto-primitives-shelley}). -As global constants, these values can only be -changed by updating the software. +The constants $\SlotsPrior$ and $\StartRewards$ concern the chain stability. +The maximum number of time a KES key can be evolved before a pool operator +must create a new operational certificate is given by $\MaxKESEvo$. +\textbf{Note that if } $\MaxKESEvo$ +\textbf{is changed, the KES signature format may have to change as well.} + +Finally, $\Quorum$ determines the quorum amount needed for votes on the +protocol parameter updates and the application version updates. + Some helper functions are defined in Figure~\ref{fig:defs:protocol-parameters-helpers}. The $\fun{minfee}$ function calculates the minimum fee that must be paid by a transaction. @@ -127,7 +136,10 @@ \section{Protocol Parameters} \begin{array}{r@{~\in~}lr} \SlotsPerEpoch & \N & \text{slots per epoch} \\ \SlotsPerKESPeriod & \N & \text{slots per KES period} \\ - \SlotsStabilityParam & \N & \text{stability parameter} + \SlotsPrior & \Duration & \tau\text{ in \cite{ouroboros_praos}}\\ + \StartRewards & \Duration & \text{duration to start reward calculations}\\ + \MaxKESEvo & \N & \text{maximum KES key evolutions}\\ + \Quorum & \N & \text{quorum for update system votes}\\ \end{array} \end{equation*} % @@ -141,12 +153,12 @@ \section{Protocol Parameters} \begin{align*} \fun{minfee} & \in \PParams \to \Tx \to \Coin & \text{minimum fee}\\ \fun{minfee} & ~\var{pp}~\var{tx} = - (\fun{a}~\var{pp}) * \fun{txSize}~\var{tx} + (\fun{b}~\var{pp}) + (\fun{a}~\var{pp}) \cdot \fun{txSize}~\var{tx} + (\fun{b}~\var{pp}) \\ \\ \fun{epoch} & \in ~ \Slot \to \Epoch & \text{epoch of a slot} \\ - \fun{epoch} & ~\var{slot} = \var{slot}~\mathsf{div}~\SlotsPerEpoch + \fun{epoch} & ~\var{slot} = \var{slot}~/~\SlotsPerEpoch \\ \\ \fun{firstSlot} & \in ~ \Epoch \to \Slot @@ -157,7 +169,7 @@ \section{Protocol Parameters} \\ \fun{kesPeriod} & \in ~ \Slot \to \KESPeriod & \text{KES period of a slot} \\ - \fun{kesPeriod} & ~\var{slot} = \var{slot}~\mathsf{div}~\SlotsPerKESPeriod + \fun{kesPeriod} & ~\var{slot} = \var{slot}~/~\SlotsPerKESPeriod \end{align*} % \caption{Helper functions for the Protocol Parameters} diff --git a/shelley/chain-and-ledger/formal-spec/transactions.tex b/shelley/chain-and-ledger/formal-spec/transactions.tex index 5548dfbd0bb..57a840ca8e0 100644 --- a/shelley/chain-and-ledger/formal-spec/transactions.tex +++ b/shelley/chain-and-ledger/formal-spec/transactions.tex @@ -22,55 +22,20 @@ \section{Transactions} For reward calculation rules, see Section \ref{sec:reward-overview}, and for the rule for collecting rewards, see Section \ref{sec:utxo-trans}. \item Update proposals for protocol parameters and software. + The update system will be explained in Section \ref{sec:update}. + \item $\PPUpdate$, the protocol parameter upates. + \item $\AVUpdate$, the updates to Shelley software (applications). \end{itemize} -In the derived types, $\Metadata$ and $\Applications$ are values -that contain versions of current and next versions of applications. -The $\ApName$ uniquely identifies a specific kind of application (e.g. -the wallet), and the associated $\ApVer$ is the specific version of that -application. The associated $\Metadata$ value gives the \textit{next possible} -versions of the given application. It is a mapping of system tags to hashes of -installer binaries, and is needed for the update mechanism. -The update proposal type $\Update$ is a pair of - -\begin{itemize} - \item $\PPUpdate$, the protocol parameter upates - \item $\AVUpdate$, the updates to Shelley software (applications) -\end{itemize} - -The $\PPUpdate$ has to do with changing rules and constants of the ledger -protocol. The relationship between the rule update procedure and updating the -node software that implements these rules is outlined in the next section -(see Section \ref{sec:update}). - -Note that both of these finite maps are indexed by the hashes of the keys of -entities proposing the given -updates, $\KeyHashGen$. -We use the abstract type $\KeyHashGen$ to represent hashes of genesis -(public verification) keys, which have type $\VKeyGen$. -Genesis keys are the keys belonging to the federated -nodes running the Cardano system currently (also referred to as core nodes). -The the regular user verification keys are of a type $\VKey$, distinct from the -genesis key type, $\VKeyGen$. Similarly, the type hashes of these -are distinct, $\KeyHash$ and $\KeyHashGen$ respectively. - -Currently, updates -can only be proposed and voted on by the owners of the genesis keys. -The process of decentralization will result in the core nodes gradually giving up -some of their priviledges and responsibilities to the other system nodes. -The aim is for these nodes to eventually give them \textit{all} up. -The intent is that in the future, the update proposal mechanism will -be decentralized as well, and allow all nodes to participate (but likely -not as a feature in the Shelley release). -For more on the decentralization process, -see \ref{sec:new-epoch-trans}. - A transaction, $\Tx$, consists of: \begin{itemize} \item The transaction body. - \item A collection of witnesses, represented as a finite map from payment verification keys - to signatures. + \item A pair of: + \begin{itemize} + \item A finite map from payment verification keys to signatures. + \item A finite map from script hashes to scripts. + \end{itemize} \end{itemize} Additionally, the $\UTxO$ type will be used by the ledger state to store all the @@ -116,7 +81,12 @@ \section{Transactions} & \Wdrl & \AddrRWD \mapsto \Coin & \text{reward withdrawal} - \\ + \end{array} + \end{equation*} + \emph{Derived types (update system)} + % + \begin{equation*} + \begin{array}{r@{~\in~}l@{\qquad=\qquad}lr} \var{pup} & \PPUpdate & \KeyHashGen \mapsto \Ppm \mapsto \Seed @@ -210,7 +180,7 @@ \section{Transactions} \begin{align*} \fun{validateScript} & \in\Script\to\Tx\to\Bool & \text{validate script} \\ - \fun{validateScript} & \var{msig}~\var{tx}= + \fun{validateScript} & ~\var{msig}~\var{tx}= \begin{cases} \fun{evalMultiSigScript}~msig~vhks & \text{if}~msig \in\MSig \\ \mathsf{False} & \text{otherwise} @@ -227,5 +197,6 @@ \section{Transactions} $\fun{txinsVKey}$ and $\fun{txinsScript}$ which partition the set of transaction inputs of the transaction into those that are locked with a private key and those that are locked via a script. +It also defines $\fun{validateScript}$, which validates the multisignature scripts. \clearpage diff --git a/shelley/chain-and-ledger/formal-spec/update.tex b/shelley/chain-and-ledger/formal-spec/update.tex index f84d824e31f..25621320577 100644 --- a/shelley/chain-and-ledger/formal-spec/update.tex +++ b/shelley/chain-and-ledger/formal-spec/update.tex @@ -7,7 +7,7 @@ \section{Update Proposal Mechanism} updates. In this chapter we outline rules for genesis keys \textit{proposing} both protocol parameter and application version updates, as well as voting on whether a particular -software update is an acceptable future option (again, only genesis keys vote on this). +software update is an acceptable future option. For rules regarding the \textit{adoption} of protocol parameter updates, see \ref{sec:pparam-update}. For rules regarding adoption of new software versions see \ref{sec:software-updates}. @@ -19,7 +19,7 @@ \section{Update Proposal Mechanism} \textbf{Genesis Key Delegations.} The environment for both protocol parameter and application version updates contains -the value $\var{dms}$, which is a finite map indexed by genesis key hashes. +the value $\var{genDelegs}$, which is a finite map indexed by genesis key hashes. This is the genesis key delegations. During the Byron era, they are all already delegated to some $\KeyHash$, and these delegations are inherited through the Byron-Shelley transition (see \ref{sec:byron-to-shelley}). @@ -37,6 +37,38 @@ \section{Update Proposal Mechanism} on the ledger in addition to the currently accepted protocol parameters and application versions. +\subsection{Descriptions of the Data} +\label{sec:update-types} + +The types were defined in Figure~\ref{fig:defs:utxo-shelley}. +In the derived types, $\Metadata$ and $\Applications$ are values +that contain versions of current and next versions of applications. +The $\ApName$ uniquely identifies a specific kind of application (e.g. +the wallet), and the associated $\ApVer$ is the specific version of that +application. The associated $\Metadata$ value gives the \textit{next possible} +versions of the given application. It is a mapping of system tags to hashes of +installer binaries, and is needed for the update mechanism. +The update proposal type $\Update$ is a pair of $\PPUpdate$ and $\AVUpdate$. +$\PPUpdate$ allows for changing protocol parameters, +and $\AVUpdate$ allows for updating the software versions. + +Note that both of these finite maps are indexed by the hashes of the keys of +entities proposing the given updates, $\KeyHashGen$. +We use the abstract type $\KeyHashGen$ to represent hashes of genesis +(public verification) keys, which have type $\VKeyGen$. +Genesis keys are the keys belonging to the federated +nodes running the Cardano system currently (also referred to as core nodes). +The the regular user verification keys are of a type $\VKey$, distinct from the +genesis key type, $\VKeyGen$. Similarly, the type hashes of these +are distinct, $\KeyHash$ and $\KeyHashGen$ respectively. + +Currently, updates can only be proposed and voted on by the owners of the genesis keys. +The process of decentralization will result in the core nodes gradually giving up +some of their priviledges and responsibilities to the network, +eventually give them \textit{all} up. +The update proposal mechanism will not be decentralization in the Shelley era, however. +For more on the decentralization process, see \ref{sec:new-epoch-trans}. + \subsection{Protocol Parameter Update Proposals} \label{sec:pp-proposals} @@ -63,7 +95,7 @@ \subsection{Protocol Parameter Update Proposals} $\fun{firstSlot}~((\fun{epoch}~\var{slot}) + 1) - \fun{SlotsPrior}$, there is a \emph{PPUpdateTooEarly} failure. \item In the case of \var{pup} being non-empty, if the check $\dom pup \subseteq - \dom dms$ fails, there is a \emph{NonGenesisUpdate} failure as only genesis keys + \dom genDelegs$ fails, there is a \emph{NonGenesisUpdate} failure as only genesis keys can be used in the protocol parameter update. \item If a protocol parameter update in \var{pup} cannot follow the current protocol parameter, there is a \emph{PVCannotFollow} failure. @@ -88,7 +120,7 @@ \subsection{Protocol Parameter Update Proposals} \begin{array}{r@{~\in~}lr} \var{slot} & \Slot & \text{current slot}\\ \var{pp} & \PParams & \text{protocol parameters}\\ - \var{dms} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ + \var{genDelegs} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ \end{array} \right) \end{equation*} @@ -114,7 +146,7 @@ \subsection{Protocol Parameter Update Proposals} \begin{array}{r} \var{slot}\\ \var{pp}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \var{pup_s}\trans{ppup}{pup}\var{pup_s} } @@ -127,7 +159,7 @@ \subsection{Protocol Parameter Update Proposals} { \var{pup}\neq\emptyset & - \dom{pup}\subseteq\dom{dms} + \dom{pup}\subseteq\dom{genDelegs} \\ \forall\var{ps}\in\range{pup},~ \var{pv}\mapsto\var{v}\in\var{ps}\implies\fun{pvCanFollow}~(\fun{pv}~\var{pp})~\var{v} @@ -138,7 +170,7 @@ \subsection{Protocol Parameter Update Proposals} \begin{array}{r} \var{slot}\\ \var{pp}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \var{pup_s} @@ -174,6 +206,10 @@ \subsection{Protocol Parameter Update Proposals} versions to a finite map of applications using right override. This helper function will be used in the ledger update. +\textbf{Note that} $\fun{votedValue}$ +\textbf{is only well-defined if } $\Quorum$ +\textbf{is greater than half the number of core nodes, i.e.} +$\Quorum > |\var{genDelegs}|/2$ \textbf{.} %% %% Figure - Helper Function for Consensus of Update Proposals %% @@ -182,7 +218,7 @@ \subsection{Protocol Parameter Update Proposals} & \fun{votedValue_T} \in (\KeyHashGen\mapsto\type{T}) \to \type{T}^?\\ & \fun{votedValue_T}~\var{vs} = \begin{cases} - t & \exists t\in\range{vs}~(|vs\restrictrange t|\geq 5) \\ + t & \exists t\in\range{vs}~(|vs\restrictrange t|\geq \Quorum) \\ \Nothing & \text{otherwise} \\ \end{cases} \end{align*} @@ -277,7 +313,7 @@ \subsection{Application Version Update Proposals} The AVUP rule has three predicate failures: \begin{itemize} \item In the case of \var{aup} being non-empty, if the check $\dom aup \subseteq - \dom dms$ fails, there is a \emph{NonGenesisUpdate} failure as only genesis keys + \dom genDelegs$ fails, there is a \emph{NonGenesisUpdate} failure as only genesis keys can be used in the application version update. \item In the case of \var{aup} being non-empty, if any of the application names in the proposal are invalid, there is a \emph{InvalidName} failure. @@ -296,7 +332,7 @@ \subsection{Application Version Update Proposals} \left( \begin{array}{r@{~\in~}lr} \var{slot} & \Slot & \text{current slot}\\ - \var{dms} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ + \var{genDelegs} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ \end{array} \right) \end{equation*} @@ -333,7 +369,7 @@ \subsection{Application Version Update Proposals} { \begin{array}{l} \var{slot}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \left( @@ -361,7 +397,7 @@ \subsection{Application Version Update Proposals} { \var{aup}\neq\emptyset & - \dom{\var{aup}}\subseteq\dom{\var{dms}} + \dom{\var{aup}}\subseteq\dom{\var{genDelegs}} \\ \forall \wcard\mapsto\var{vote}\in\var{aup},\forall n\in\dom{vote},~ \fun{apNameValid}~\var{v} @@ -381,7 +417,7 @@ \subsection{Application Version Update Proposals} { \begin{array}{l} \var{slot}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \left( @@ -409,7 +445,7 @@ \subsection{Application Version Update Proposals} { \var{aup}\neq\emptyset & - \dom{\var{aup}}\subseteq\dom{\var{dms}} + \dom{\var{aup}}\subseteq\dom{\var{genDelegs}} \\ \forall \wcard\mapsto\var{vote}\in\var{aup},\forall n\in\dom{vote},~ \fun{apNameValid}~\var{v} @@ -431,7 +467,7 @@ \subsection{Application Version Update Proposals} { \begin{array}{l} \var{slot}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \left( @@ -472,7 +508,7 @@ \subsection{Application Version Update Proposals} \begin{array}{r@{~\in~}lr} \var{slot} & \Slot & \text{current slot}\\ \var{pp} & \PParams & \text{protocol parameters}\\ - \var{dms} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ + \var{genDelegs} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ \end{array} \right) \end{equation*} @@ -511,7 +547,7 @@ \subsection{Application Version Update Proposals} \begin{array}{r} \var{slot} \\ \var{pp} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array} } \vdash @@ -522,7 +558,7 @@ \subsection{Application Version Update Proposals} { \begin{array}{r} \var{slot} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array} } \vdash @@ -550,7 +586,7 @@ \subsection{Application Version Update Proposals} \begin{array}{r} \var{slot}\\ \var{pp} \\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \left( diff --git a/shelley/chain-and-ledger/formal-spec/utxo.tex b/shelley/chain-and-ledger/formal-spec/utxo.tex index a6d24c3c688..cb884570f50 100644 --- a/shelley/chain-and-ledger/formal-spec/utxo.tex +++ b/shelley/chain-and-ledger/formal-spec/utxo.tex @@ -38,6 +38,7 @@ \subsection{UTxO Transitions} \label{sec:utxo-trans} Figure~\ref{fig:functions:utxo} defines functions needed for the UTxO transition system. +See Figure~\ref{fig:defs:utxo-shelley} for most of the definitions used in the transition system. \begin{itemize} @@ -59,7 +60,7 @@ \subsection{UTxO Transitions} withdrawals and stake credential deposit refunds. Some of the definitions used in this function will be defined in Section~\ref{sec:deps-refunds}. In particular, $\fun{keyRefunds}$ is defined in - Figure~\ref{fig:functions:deposits-refunds} and $\StakeDelegs$ is defined in + Figure~\ref{fig:functions:deposits-refunds} and $\StakeCreds$ is defined in Figure~\ref{fig:delegation-defs}. \item The calculation $\fun{produced}$ gives the value produced by the transaction $\var{tx}$ @@ -101,12 +102,12 @@ \subsection{UTxO Transitions} & \text{withdrawal balance} \\ & \fun{wbalance} ~ ws = \sum_{(\wcard\mapsto c)\in\var{ws}} c \nextdef - & \fun{consumed} \in \PParams \to \UTxO \to \StakeDelegs \to \Wdrl \to \Tx \to \Coin + & \fun{consumed} \in \PParams \to \UTxO \to \StakeCreds \to \Wdrl \to \Tx \to \Coin & \text{value consumed} \\ - & \consumed{pp}{utxo}{stdelegs}{rewards}~{tx} = \\ + & \consumed{pp}{utxo}{stkCreds}{rewards}~{tx} = \\ & ~~\ubalance{(\txins{tx} \restrictdom \var{utxo})} + \fun{wbalance}~(\fun{txwdrls}~{tx}) \\ - & ~~ + \keyRefunds{pp}{stdelegs}{tx} \\ + & ~~ + \keyRefunds{pp}{stkCreds}{tx} \\ \nextdef & \fun{produced} \in \PParams \to \StakePools \to \Tx \to \Coin & \text{value produced} \\ @@ -144,6 +145,7 @@ \subsection{UTxO Transitions} \item The current UTxO. \item The deposit pot. \item The fee pot. + \item The update state (see Figure~\ref{fig:ts-types:update}). \end{itemize} The signal for the UTxO transition is a transaction. @@ -155,9 +157,9 @@ \subsection{UTxO Transitions} \begin{array}{r@{~\in~}lr} \var{slot} & \Slot & \text{current slot}\\ \var{pp} & \PParams & \text{protocol parameters}\\ - \var{stdelegs} & \StakeDeleg & \text{stake credential}\\ + \var{stkCreds} & \StakeCreds & \text{stake credential}\\ \var{stpools} & \StakePools & \text{stake pool}\\ - \var{dms} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ + \var{genDelegs} & \KeyHashGen\mapsto\KeyHash & \text{genesis key delegations} \\ \end{array} \right) \end{equation*} @@ -293,7 +295,7 @@ \subsection{UTxO Transitions} & \minfee{pp}{tx} \leq \txfee{tx} & \txins{tx} \subseteq \dom \var{utxo} \\ - \consumed{pp}{utxo}{stdelegs}{rewards}~{tx} = \produced{pp}{stpools}~{tx} + \consumed{pp}{utxo}{stkCreds}{rewards}~{tx} = \produced{pp}{stpools}~{tx} \\ ~ \\ @@ -301,7 +303,7 @@ \subsection{UTxO Transitions} \begin{array}{r} \var{slot} \\ \var{pp} \\ - \var{dms} \\ + \var{genDelegs} \\ \end{array} } \vdash \var{ups} \trans{\hyperref[fig:rules:update]{up}}{\fun{txup}~\var{tx}} \var{ups'} @@ -314,9 +316,9 @@ \subsection{UTxO Transitions} \\ ~ \\ - \var{refunded} \leteq \keyRefunds{pp}{stdelegs}~{tx} + \var{refunded} \leteq \keyRefunds{pp}{stkCreds}~{tx} \\ - \var{decayed} \leteq \decayedTx{pp}{stdelegs}~{tx} + \var{decayed} \leteq \decayedTx{pp}{stkCreds}~{tx} \\ \var{depositChange} \leteq (\deposits{pp}~{stpools}~{\txcerts{tx}}) - (\var{refunded} + \var{decayed}) @@ -325,9 +327,9 @@ \subsection{UTxO Transitions} \begin{array}{r} \var{slot}\\ \var{pp}\\ - \var{stdelegs}\\ + \var{stkCreds}\\ \var{stpools}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \left( @@ -391,7 +393,7 @@ \subsection{Deposits and Refunds} \item The function $\fun{keyRefund}$, calculates the refund for an individual stake credential registration deposit, based on the slot when it was created and the slot passed to the function. The creation slot should always exist - in the map $\var{stdelegs}$ passed to the function and this would be a good + in the map $\var{stkCreds}$ passed to the function and this would be a good property to prove about the transition system. \item The function $\fun{keyRefunds}$, in turn, uses $\fun{keyRefund}$ to calculate the total value to be refunded to all individual key deregistration certificate authors @@ -470,25 +472,25 @@ \subsection{Deposits and Refunds} \left(d_{\min}+(1-d_{\min})\cdot e^{-\lambda\cdot\delta}\right)} \nextdef & \fun{keyRefund} \in \Coin \to \unitInterval \to \posReals \to \\ - & ~~~~~\StakeDelegs \to \Slot \to \DCertDeRegKey \to \Coin + & ~~~~~\StakeCreds \to \Slot \to \DCertDeRegKey \to \Coin & \text{key refund for a certificate} \\ - & \keyRefund{\dval}{d_{\min}}{\lambda}{stdelegs}{slot}{c} =\\ + & \keyRefund{\dval}{d_{\min}}{\lambda}{stkCreds}{slot}{c} =\\ & ~~~~~\begin{cases} - 0 & \text{if}~\cwitness c \notin \dom stdelegs \\ + 0 & \text{if}~\cwitness c \notin \dom stkCreds \\ \refund{\dval}{d_{\min}}{\lambda}{\delta} & \text{otherwise} \end{cases}\\ & \begin{array}{lr@{~=~}l} \where - &\delta & \slotminus{slot}{(stdelegs~(\cwitness c))}\\ + &\delta & \slotminus{slot}{(stkCreds~(\cwitness c))}\\ \end{array}\\ \nextdef - & \fun{keyRefunds} \in \PParams \to \StakeDelegs \to \Tx \to \Coin + & \fun{keyRefunds} \in \PParams \to \StakeCreds \to \Tx \to \Coin & \text{key refunds for a transaction} \\ - & \keyRefunds{pp}{stdelegs}{tx} =\\ + & \keyRefunds{pp}{stkCreds}{tx} =\\ & ~~~~~ \sum\limits_{\substack{c \in (\txcerts{tx} \\ \cap \DCertDeRegKey)}} - \keyRefund{\dval}{d_{\min}}{\lambda}{stdelegs}{(\txttl{tx})}{c}\\ + \keyRefund{\dval}{d_{\min}}{\lambda}{stkCreds}{(\txttl{tx})}{c}\\ & \begin{array}{lr@{~=~}l} \where \\ @@ -504,31 +506,31 @@ \subsection{Deposits and Refunds} \begin{figure}[htb] \begin{align*} & \fun{decayedKey} \in - \PParams \to \StakeDelegs \to \Slot \to \DCertDeRegKey \to \Coin + \PParams \to \StakeCreds \to \Slot \to \DCertDeRegKey \to \Coin & \text{decayed since epoch} \\ - & \decayedKey{pp}{stdelegs}{cslot}{c} =\\ + & \decayedKey{pp}{stkCreds}{cslot}{c} =\\ & \begin{cases} - 0 & \text{if}~\cwitness c \notin \dom stdelegs\\ + 0 & \text{if}~\cwitness c \notin \dom stkCreds\\ \var{epochRefund} - \var{currentRefund} & \text{otherwise} \end{cases}\\ & \begin{array}{lr@{~=~}l} \where - & \var{created} & \var{stdelegs}~(\cwitness~\var{c}) \\ + & \var{created} & \var{stkCreds}~(\cwitness~\var{c}) \\ & \var{start} & \mathsf{max}~(\firstSlot{\epoch{cslot}})~created \\ - & \var{epochRefund} & \keyRefund{\dval}{d_{\min}}{\lambda}{stdelegs}{start}{c} \\ - & \var{currentRefund} & \keyRefund{\dval}{d_{\min}}{\lambda}{stdelegs}{cslot}{c} \\ + & \var{epochRefund} & \keyRefund{\dval}{d_{\min}}{\lambda}{stkCreds}{start}{c} \\ + & \var{currentRefund} & \keyRefund{\dval}{d_{\min}}{\lambda}{stkCreds}{cslot}{c} \\ & \dval & \fun{keyDeposit}~\var{pp}\\ & d_{\min} & \fun{keyMinRefund}~\var{pp}\\ & \lambda & \fun{keyDecayRate}~\var{pp}\\ \end{array}\\ \nextdef - & \fun{decayedTx} \in \PParams \to \StakeDelegs \to \Tx \to \Coin + & \fun{decayedTx} \in \PParams \to \StakeCreds \to \Tx \to \Coin & \text{decayed deposit portions} \\ - & \decayedTx{pp}{stdelegs}{tx} =\\ + & \decayedTx{pp}{stkCreds}{tx} =\\ & \sum\limits_{\substack{c \in (\txcerts{tx} \\ \cap \DCertDeRegKey)}} - \decayedKey{pp}{stdelegs}{(\txttl{tx})}{c}\\ + \decayedKey{pp}{stkCreds}{(\txttl{tx})}{c}\\ \end{align*} \caption{Functions used in Deposits - Decay} \label{fig:functions:deposits-decay} @@ -569,12 +571,12 @@ \subsection{Witnesses} \begin{align*} & \fun{propWits} \in \Update \to (\KeyHashGen\mapsto\VKey) \to \powerset{\KeyHash} & \text{hashkeys for proposals} \\ - & \fun{propWits}~(\var{pup},~\var{aup})~\var{dms} = \\ + & \fun{propWits}~(\var{pup},~\var{aup})~\var{genDelegs} = \\ & ~~\left\{ \hashKey{vkey} \mid \var{gkey}\mapsto\var{vkey}\in - \left(\left(\dom{\var{pup}}\cup\dom{\var{aup}}\right)\restrictdom\var{dms}\right) + \left(\left(\dom{\var{pup}}\cup\dom{\var{aup}}\right)\restrictdom\var{genDelegs}\right) \right\} \end{align*} @@ -582,13 +584,13 @@ \subsection{Witnesses} & \hspace{-0.8cm}\fun{witsVKeyNeeded} \in \UTxO \to \Tx \to (\KeyHashGen\mapsto\VKey) \to \powerset{\KeyHash} & \text{required key hashes} \\ - & \hspace{-0.8cm}\fun{witsVKeyNeeded}~\var{utxo}~\var{tx}~\var{dms} = \\ + & \hspace{-0.8cm}\fun{witsVKeyNeeded}~\var{utxo}~\var{tx}~\var{genDelegs} = \\ & ~~\{ \fun{paymentHK}~a \mid i \mapsto (a, \wcard) \in \var{utxo},~i\in\fun{txinsVKey}~{tx} \} \\ \cup & ~~ \{\fun{stakeCred_r}~a\mid a\mapsto \wcard \in \AddrRWDVKey \restrictdom \txwdrls{tx}\}\\ \cup & ~~\{\cwitness{c} \mid c \in \txcerts{tx} \setminus \DCertMir\}~\cup \\ - \cup & ~~\fun{propWits}~(\fun{txup}~\var{tx})~\var{dms} \\ + \cup & ~~\fun{propWits}~(\fun{txup}~\var{tx})~\var{genDelegs} \\ \cup & ~~\bigcup_{\substack{c \in \txcerts{tx} \\ ~c \in\DCertRegPool}} \fun{poolOwners}~{c} \end{align*} \begin{align*} @@ -635,38 +637,37 @@ \subsection{Witnesses} \label{eq:utxo-witness-inductive-shelley} \inference[UTxO-wit] { - (utxo, \wcard, \wcard) \leteq \var{utxoSt} \\~\\ - \forall \var{hs} \mapsto \var{validator} \in \fun{txwitsScript}~{tx},\\ + (utxo, \wcard, \wcard) \leteq \var{utxoSt} \\ + \var{witsKeyHashes} \leteq \{\fun{hashKey}~\var{vk} \vert \var{vk} \in + \dom (\txwitsVKey{tx}) \}\\~\\ + \forall \var{hs} \mapsto \var{validator} \in \fun{txwitsScript}~{tx},\\ \fun{hashScript}~\var{validator} = \var{hs} \wedge \fun{validateScript}~\var{validator}~\var{tx}\\~\\ \fun{scriptsNeeded}~\var{utxo}~\var{tx} = \dom (\fun{txwitsScript}~{tx}) \\~\\ \forall \var{vk} \mapsto \sigma \in \txwitsVKey{tx}, \mathcal{V}_{\var{vk}}{\serialised{\txbody{tx}}}_{\sigma} \\ - \fun{witsVKeyNeeded}~{utxo}~{tx}~{dms} \subseteq \{ \hashKey \var{vk} \mid - \var{vk}\in\dom{(\txwitsVKey{tx})} \} + \fun{witsVKeyNeeded}~{utxo}~{tx}~{genDelegs} \subseteq witsKeyHashes \\~\\ genSig \leteq \left\{ - \fun{hashKey}~vk \vert gkey\mapsto vk \in\var{dms} + \fun{hashKey}~gkey \vert gkey \in\dom{genDelegs} \right\} \cap - \left\{ - \fun{hashKey}~\var{vk} \vert \var{vk}\in\dom{(\txwitsVKey{tx})} - \right\} + \var{witsKeyHashes} \\ \left\{ c\in\txcerts{tx}~\cap\DCertMir - \right\} \neq\emptyset \implies \vert genSig\vert \geq 5 \wedge + \right\} \neq\emptyset \implies \vert genSig\vert \geq \Quorum \wedge \fun{d}~\var{pp} > 0 \\~\\ { \begin{array}{r} \var{slot}\\ \var{pp}\\ - \var{stdelegs}\\ + \var{stkCreds}\\ \var{stpools}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} } \vdash \var{utxoSt} \trans{\hyperref[fig:rules:utxo-shelley]{utxo}}{tx} @@ -676,9 +677,9 @@ \subsection{Witnesses} \begin{array}{r} \var{slot}\\ \var{pp}\\ - \var{stdelegs}\\ + \var{stkCreds}\\ \var{stpools}\\ - \var{dms}\\ + \var{genDelegs}\\ \end{array} \vdash \var{utxoSt} \trans{utxow}{tx} \varUpdate{\var{utxoSt'}} } diff --git a/shelley/design-spec/Makefile b/shelley/design-spec/Makefile index d41718efeb4..30f58248505 100644 --- a/shelley/design-spec/Makefile +++ b/shelley/design-spec/Makefile @@ -19,7 +19,7 @@ all: $(DOCNAME).pdf ## ## CUSTOM BUILD RULES ## -${DOCNAMe}.bbl: $(DOCNAME).tex +${DOCNAME}.bbl: $(DOCNAME).tex touch $(DOCNAME).bbl diff --git a/shelley/design-spec/cm-super-t1.enc b/shelley/design-spec/cm-super-t1.enc new file mode 100644 index 00000000000..6bad7c3d18b --- /dev/null +++ b/shelley/design-spec/cm-super-t1.enc @@ -0,0 +1,290 @@ +% This file is generated from `T1uni.map' and `glyphlist.txt', `gl-other.txt' +% +% LIGKERN hyphen hyphen =: endash ; endash hyphen =: emdash ; +% LIGKERN quoteleft quoteleft =: quotedblleft ; +% LIGKERN quoteright quoteright =: quotedblright ; +% LIGKERN comma comma =: quotedblbase ; less less =: guillemotleft ; +% LIGKERN greater greater =: guillemotright ; +% LIGKERN f f =: ff ; f i =: fi ; f l =: fl ; ff i =: ffi ; ff l =: ffl ; +% +% LIGKERN space {} * ; * {} space ; zero {} * ; * {} zero ; +% LIGKERN one {} * ; * {} one ; two {} * ; * {} two ; +% LIGKERN three {} * ; * {} three ; four {} * ; * {} four ; +% LIGKERN five {} * ; * {} five ; six {} * ; * {} six ; +% LIGKERN seven {} * ; * {} seven ; eight {} * ; * {} eight ; +% LIGKERN nine {} * ; * {} nine ; +% +/T1Encoding [ +% 0x00 +/grave +/acute +/circumflex +/tilde +/dieresis +/hungarumlaut +/ring +/caron +/breve +/macron +/dotaccent +/cedilla +/ogonek +/quotesinglbase +/guilsinglleft +/guilsinglright +% 0x10 +/quotedblleft +/quotedblright +/quotedblbase +/guillemotleft +/guillemotright +/endash +/emdash +/afii61664 +/perthousandzero % PERTHOUSAND ZERO +/dotlessi +/dotlessj +/ff +/fi +/fl +/ffi +/ffl +% 0x20 +/uni2423 +/exclam +/quotedbl +/numbersign +/dollar +/percent +/ampersand +/quoteright +/parenleft +/parenright +/asterisk +/plus +/comma +/hyphen +/period +/slash +% 0x30 +/zero +/one +/two +/three +/four +/five +/six +/seven +/eight +/nine +/colon +/semicolon +/less +/equal +/greater +/question +% 0x40 +/at +/A +/B +/C +/D +/E +/F +/G +/H +/I +/J +/K +/L +/M +/N +/O +% 0x50 +/P +/Q +/R +/S +/T +/U +/V +/W +/X +/Y +/Z +/bracketleft +/backslash +/bracketright +/asciicircum +/underscore +% 0x60 +/quoteleft +/a +/b +/c +/d +/e +/f +/g +/h +/i +/j +/k +/l +/m +/n +/o +% 0x70 +/p +/q +/r +/s +/t +/u +/v +/w +/x +/y +/z +/braceleft +/bar +/braceright +/asciitilde +/hyphen.alt % HANGING HYPHEN +% 0x80 +/Abreve +/Aogonek +/Cacute +/Ccaron +/Dcaron +/Ecaron +/Eogonek +/Gbreve +/Lacute +/Lcaron +/Lslash +/Nacute +/Ncaron +/Eng +/Ohungarumlaut +/Racute +% 0x90 +/Rcaron +/Sacute +/Scaron +/Scedilla +/Tcaron +/Tcommaaccent +/Uhungarumlaut +/Uring +/Ydieresis +/Zacute +/Zcaron +/Zdotaccent +/IJ +/Idotaccent +/dcroat +/section +% 0xA0 +/abreve +/aogonek +/cacute +/ccaron +/dcaron +/ecaron +/eogonek +/gbreve +/lacute +/lcaron +/lslash +/nacute +/ncaron +/eng +/ohungarumlaut +/racute +% 0xB0 +/rcaron +/sacute +/scaron +/scedilla +/tcaron +/tcommaaccent +/uhungarumlaut +/uring +/ydieresis +/zacute +/zcaron +/zdotaccent +/ij +/exclamdown +/questiondown +/sterling +% 0xC0 +/Agrave +/Aacute +/Acircumflex +/Atilde +/Adieresis +/Aring +/AE +/Ccedilla +/Egrave +/Eacute +/Ecircumflex +/Edieresis +/Igrave +/Iacute +/Icircumflex +/Idieresis +% 0xD0 +/Eth +/Ntilde +/Ograve +/Oacute +/Ocircumflex +/Otilde +/Odieresis +/OE +/Oslash +/Ugrave +/Uacute +/Ucircumflex +/Udieresis +/Yacute +/Thorn +/SS % Germandbls +% 0xE0 +/agrave +/aacute +/acircumflex +/atilde +/adieresis +/aring +/ae +/ccedilla +/egrave +/eacute +/ecircumflex +/edieresis +/igrave +/iacute +/icircumflex +/idieresis +% 0xF0 +/eth +/ntilde +/ograve +/oacute +/ocircumflex +/otilde +/odieresis +/oe +/oslash +/ugrave +/uacute +/ucircumflex +/udieresis +/yacute +/thorn +/germandbls % or /germandbls.alt +] defef diff --git a/shelley/design-spec/delegation_design_spec.bbl b/shelley/design-spec/delegation_design_spec.bbl new file mode 100644 index 00000000000..aee957776ae --- /dev/null +++ b/shelley/design-spec/delegation_design_spec.bbl @@ -0,0 +1,44 @@ +\begin{thebibliography}{DGKR17} +\expandafter\ifx\csname url\endcsname\relax + \def\url#1{\texttt{#1}}\fi +\expandafter\ifx\csname doi\endcsname\relax + \def\doi#1{\burlalt{doi:#1}{http://dx.doi.org/#1}}\fi +\expandafter\ifx\csname urlprefix\endcsname\relax\def\urlprefix{URL }\fi +\expandafter\ifx\csname href\endcsname\relax + \def\href#1#2{#2}\fi +\expandafter\ifx\csname burlalt\endcsname\relax + \def\burlalt#1#2{\href{#2}{#1}}\fi + +\bibitem[BKKS18]{bkks2018} +L.~Bruenjes, A.~Kiayias, E.~Koutsoupias, and A.-P. Stouka. +\newblock Reward sharing schemes for stake pools. +\newblock Computer Science and Game Theory (cs.GT) arXiv:1807.11218, 2018. + +\bibitem[DGKR17]{ouroboros_praos} +B.~M. David, P.~Gazi, A.~Kiayias, and A.~Russell. +\newblock Ouroboros praos: An adaptively-secure, semi-synchronous + proof-of-stake protocol. +\newblock {\em IACR Cryptology ePrint Archive}, 2017:573, 2017. + +\bibitem[KRDO17]{ouroboros_classic} +A.~Kiayias, A.~Russell, B.~David, and R.~Oliynykov. +\newblock Ouroboros: A provably secure proof-of-stake blockchain protocol. +\newblock In {\em Advances in Cryptology -- CRYPTO 2017}, volume 10401 of {\em + Security and Cryptology}. Springer International Publishing, 2017. +\newblock \doi{10.1007/978-3-319-63688-7}. + +\bibitem[MMM01]{cryptoeprint:2001:034} +T.~Malkin, D.~Micciancio, and S.~Miner. +\newblock Composition and efficiency tradeoffs for forward-secure digital + signatures. +\newblock Cryptology ePrint Archive, Report 2001/034, 2001. +\newblock \url{https://eprint.iacr.org/2001/034}. + +\bibitem[Wui12]{bip32} +P.~Wuille. +\newblock Hierarchical deterministic wallets, February 2012. +\newblock + \urlprefix\url{https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki}. +\newblock BIP-32. + +\end{thebibliography} diff --git a/shelley/design-spec/sftt1200.pfb b/shelley/design-spec/sftt1200.pfb new file mode 100644 index 00000000000..41cb80e2c5d Binary files /dev/null and b/shelley/design-spec/sftt1200.pfb differ diff --git a/stack.yaml b/stack.yaml index 7751b401f2f..0471c9f93ba 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: https://raw.githubusercontent.com/input-output-hk/cardano-prelude/b9bf62f2bab90539809bee13620fe7d29b35928d/snapshot.yaml +resolver: https://raw.githubusercontent.com/input-output-hk/cardano-prelude/f12a60595dbc2436d99a198b717bf26a683b5eec/snapshot.yaml packages: - shelley/chain-and-ledger/executable-spec @@ -14,10 +14,10 @@ extra-deps: - bimap-0.4.0 - git: https://github.com/input-output-hk/cardano-prelude - commit: b9bf62f2bab90539809bee13620fe7d29b35928d + commit: f12a60595dbc2436d99a198b717bf26a683b5eec - git: https://github.com/input-output-hk/cardano-base - commit: bb262f466d659d94ed6e5500c2dc101f7c2c6b1e + commit: 5c575d46afbfe333de0ccba70b084db8302abf42 subdirs: - binary - cardano-crypto-class