diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo.hs index 45e05fd2ffd..1ddb3db860c 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo.hs @@ -56,7 +56,6 @@ import Cardano.Ledger.Shelley.Constraints ) import Cardano.Ledger.ShelleyMA.Timelocks (evalTimelock) import qualified Data.Set as Set -import qualified Plutus.V1.Ledger.Api as Plutus (validateScript) import qualified Shelley.Spec.Ledger.API as API import qualified Shelley.Spec.Ledger.BaseTypes as Shelley import Shelley.Spec.Ledger.Metadata (validMetadatum) @@ -90,7 +89,7 @@ instance -- instance API.PraosCrypto c => API.ApplyBlock (AlonzoEra c) -instance API.PraosCrypto c => API.GetLedgerView (AlonzoEra c) +instance (API.PraosCrypto c) => API.GetLedgerView (AlonzoEra c) instance (CC.Crypto c) => Shelley.ValidateScript (AlonzoEra c) where isNativeScript x = not (isPlutusScript x) @@ -105,8 +104,10 @@ instance (CC.Crypto c) => Shelley.ValidateScript (AlonzoEra c) where timelock where vhks = Set.map witKeyHash (txwitsVKey' (wits' tx)) - validateScript (PlutusScript scr) _tx = Plutus.validateScript scr + validateScript (PlutusScript _) _tx = False +-- To run a PlutusScript use Cardano.Ledger.Alonzo.TxInfo(runPLCScript) +-- To run any Alonzo Script use Cardano.Ledger.Alonzo.PlutusScriptApi(evalScripts) -- hashScript x = ... We use the default method for hashScript instance @@ -118,8 +119,7 @@ instance -- initialState :: ShelleyGenesis era -> AdditionalGenesisConfig era -> NewEpochState era initialState _ _ = error "TODO: implement initialState" -instance CC.Crypto c => UsesTxOut (AlonzoEra c) where - -- makeTxOut :: Proxy era -> Addr (Crypto era) -> Value era -> TxOut era +instance (CC.Crypto c) => UsesTxOut (AlonzoEra c) where makeTxOut _proxy addr val = TxOut addr val Shelley.SNothing type instance Core.TxOut (AlonzoEra c) = TxOut (AlonzoEra c) diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/Data.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/Data.hs index c28dd5b6397..b78c38ee786 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/Data.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/Data.hs @@ -35,7 +35,7 @@ module Cardano.Ledger.Alonzo.Data ) where -import Cardano.Binary (FromCBOR (..), ToCBOR (..), TokenType (..), peekTokenType) +import Cardano.Binary (FromCBOR (..), ToCBOR (..), TokenType (..), peekTokenType, withSlice) import Cardano.Ledger.Alonzo.Scripts ( Script (..), isPlutusScript, @@ -69,6 +69,9 @@ import Cardano.Ledger.SafeHash hashAnnotated, ) import Cardano.Prelude (HeapWords (..), heapWords0, heapWords1) +import qualified Data.ByteString as BS (ByteString, length) +import Data.ByteString.Lazy (toStrict) +import Data.ByteString.Short (toShort) import Data.Coders import qualified Data.Foldable as Foldable import qualified Data.List as List @@ -103,9 +106,15 @@ instance FromCBOR (Annotator Plutus.Data) where <*! (D $ decodeMapContentsTraverse fromCBOR fromCBOR) decPlutus 2 = Ann (SumD Plutus.List) <*! listDecodeA From decPlutus 3 = Ann (SumD Plutus.I Either String Plutus.Data +checkPlutusByteString s = + if BS.length s <= 64 + then Right (Plutus.B s) + else Left ("Plutus Bytestring in Plutus Data has length greater than 64: " ++ show (BS.length s) ++ "\n " ++ show s) + instance ToCBOR Plutus.Data where toCBOR x = encode (encPlutus x) where @@ -127,11 +136,10 @@ newtype Data era = DataConstr (MemoBytes Plutus.Data) deriving (Eq, Ord, Generic, Show) deriving newtype (SafeToHash, ToCBOR) -deriving via - (Mem Plutus.Data) - instance - (Era era) => - FromCBOR (Annotator (Data era)) +instance Typeable era => FromCBOR (Annotator (Data era)) where + fromCBOR = do + (Annotator getT, Annotator getBytes) <- withSlice fromCBOR + pure (Annotator (\fullbytes -> DataConstr (Memo (getT fullbytes) (toShort (toStrict (getBytes fullbytes)))))) instance (Crypto era ~ c) => HashAnnotated (Data era) EraIndependentData c diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/PParams.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/PParams.hs index 3d11c2e4c41..5536e32c57e 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/PParams.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/PParams.hs @@ -340,14 +340,6 @@ instance NoThunks (PParamsUpdate era) -- writing only those fields where the field is (SJust x), that is the role of -- the local function (omitStrictMaybe key x) -fromSJust :: StrictMaybe a -> a -fromSJust (SJust x) = x -fromSJust SNothing = error "SNothing in fromSJust" - -isSNothing :: StrictMaybe a -> Bool -isSNothing SNothing = True -isSNothing (SJust _) = False - encodePParamsUpdate :: PParamsUpdate era -> Encode ('Closed 'Sparse) (PParamsUpdate era) @@ -380,6 +372,14 @@ encodePParamsUpdate ppup = Word -> StrictMaybe a -> (a -> Encoding) -> Encode ('Closed 'Sparse) (StrictMaybe a) omitStrictMaybe key x enc = Omit isSNothing (Key key (E (enc . fromSJust) x)) + fromSJust :: StrictMaybe a -> a + fromSJust (SJust x) = x + fromSJust SNothing = error "SNothing in fromSJust. This should never happen, it is guarded by isSNothing." + + isSNothing :: StrictMaybe a -> Bool + isSNothing SNothing = True + isSNothing (SJust _) = False + instance (Era era) => ToCBOR (PParamsUpdate era) where toCBOR ppup = encode (encodePParamsUpdate ppup) diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxos.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxos.hs index b2b75904723..c69b60405f0 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxos.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxos.hs @@ -124,7 +124,7 @@ utxosTransition = scriptsValidateTransition :: forall era. - ( Show (Core.Value era), -- Arises because of the use of (∪) from SetAlgebra, needs Show to report errors. + ( Show (Core.Value era), -- Arises because of the use of (∪) from SetAlgebra, needs Show to report problems. Era era, Environment (Core.EraRule "PPUP" era) ~ PPUPEnv era, State (Core.EraRule "PPUP" era) ~ PPUPState era, diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxow.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxow.hs index 98e9edccaab..e14423a9125 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxow.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/Rules/Utxow.hs @@ -94,18 +94,21 @@ data AlonzoPredFail era deriving instance ( Era era, - Show (PredicateFailure (Core.EraRule "UTXO" era)) -- The Shelley UtxowPredicateFailure needs this to Show + Show (PredicateFailure (Core.EraRule "UTXO" era)), -- The Shelley UtxowPredicateFailure needs this to Show + Show (Core.Script era) ) => Show (AlonzoPredFail era) deriving instance ( Era era, - Eq (PredicateFailure (Core.EraRule "UTXO" era)) -- The Shelley UtxowPredicateFailure needs this to Eq + Eq (PredicateFailure (Core.EraRule "UTXO" era)), -- The Shelley UtxowPredicateFailure needs this to Eq + Eq (Core.Script era) ) => Eq (AlonzoPredFail era) instance ( Era era, + NoThunks (Core.Script era), NoThunks (PredicateFailure (Core.EraRule "UTXO" era)) ) => NoThunks (AlonzoPredFail era) @@ -114,7 +117,8 @@ instance ( Era era, ToCBOR (PredicateFailure (Core.EraRule "UTXO" era)), Typeable (Core.AuxiliaryData era), - Typeable (Core.Script era) + Typeable (Core.Script era), + ToCBOR (Core.Script era) ) => ToCBOR (AlonzoPredFail era) where @@ -142,7 +146,8 @@ instance FromCBOR (PredicateFailure (Core.EraRule "UTXO" era)), FromCBOR (Script era), Typeable (Core.Script era), - Typeable (Core.AuxiliaryData era) + Typeable (Core.AuxiliaryData era), + FromCBOR (Core.Script era) ) => FromCBOR (AlonzoPredFail era) where diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs index e44e824a7d5..c90605d35a3 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs @@ -496,24 +496,22 @@ instance (Typeable c, CC.Crypto c) => FromCBOR (ScriptPurpose c) where -- ======================================= class Indexable elem container where - indexOf :: elem -> container -> Word64 - atIndex :: Word64 -> container -> elem + indexOf :: elem -> container -> StrictMaybe Word64 instance Ord k => Indexable k (Set k) where - indexOf n set = fromIntegral $ Set.findIndex n set - atIndex i set = Set.elemAt (fromIntegral i) set + indexOf n set = case Set.lookupIndex n set of + Just x -> SJust (fromIntegral x) + Nothing -> SNothing instance Eq k => Indexable k (StrictSeq k) where indexOf n seqx = case StrictSeq.findIndexL (== n) seqx of - Just m -> fromIntegral m - Nothing -> error "Not found in StrictSeq" - atIndex i seqx = case StrictSeq.lookup (fromIntegral i) seqx of - Just element -> element - Nothing -> error ("No elem at index " ++ show i) + Just m -> SJust (fromIntegral m) + Nothing -> SNothing instance Ord k => Indexable k (Map.Map k v) where - indexOf n mp = fromIntegral $ Map.findIndex n mp - atIndex i mp = fst (Map.elemAt (fromIntegral i) mp) -- If one needs the value, on can use Map.Lookup + indexOf n mp = case Map.lookupIndex n mp of + Just x -> SJust (fromIntegral x) + Nothing -> SNothing rdptr :: forall era. @@ -524,11 +522,11 @@ rdptr :: ) => Core.TxBody era -> ScriptPurpose (Crypto era) -> - RdmrPtr -rdptr txb (Minting (PolicyID hash)) = RdmrPtr Mint (indexOf hash ((getField @"minted" txb) :: Set (ScriptHash (Crypto era)))) -rdptr txb (Spending txin) = RdmrPtr Spend (indexOf txin (getField @"inputs" txb)) -rdptr txb (Rewarding racnt) = RdmrPtr Rewrd (indexOf racnt (unWdrl (getField @"wdrls" txb))) -rdptr txb (Certifying d) = RdmrPtr Cert (indexOf d (getField @"certs" txb)) + StrictMaybe RdmrPtr +rdptr txb (Minting (PolicyID hash)) = RdmrPtr Mint <$> (indexOf hash ((getField @"minted" txb) :: Set (ScriptHash (Crypto era)))) +rdptr txb (Spending txin) = RdmrPtr Spend <$> (indexOf txin (getField @"inputs" txb)) +rdptr txb (Rewarding racnt) = RdmrPtr Rewrd <$> (indexOf racnt (unWdrl (getField @"wdrls" txb))) +rdptr txb (Certifying d) = RdmrPtr Cert <$> (indexOf d (getField @"certs" txb)) getMapFromValue :: Value crypto -> Map.Map (PolicyID crypto) (Map.Map AssetName Integer) getMapFromValue (Value _ m) = m @@ -544,10 +542,11 @@ indexedRdmrs :: ValidatedTx era -> ScriptPurpose (Crypto era) -> Maybe (Data era, ExUnits) -indexedRdmrs tx sp = Map.lookup rdptr' rdmrs - where - rdmrs = unRedeemers $ txrdmrs' . getField @"wits" $ tx - rdptr' = rdptr @era (getField @"body" tx) sp +indexedRdmrs tx sp = case rdptr @era (getField @"body" tx) sp of + SNothing -> Nothing + SJust policyid -> Map.lookup policyid rdmrs + where + rdmrs = unRedeemers $ txrdmrs' . getField @"wits" $ tx -- ======================================================= diff --git a/alonzo/impl/src/Cardano/Ledger/Alonzo/TxBody.hs b/alonzo/impl/src/Cardano/Ledger/Alonzo/TxBody.hs index 2245845cacc..effa766d0a5 100644 --- a/alonzo/impl/src/Cardano/Ledger/Alonzo/TxBody.hs +++ b/alonzo/impl/src/Cardano/Ledger/Alonzo/TxBody.hs @@ -141,12 +141,24 @@ deriving stock instance ) => Eq (TxOut era) +viewCompactTxOut :: + forall era. + (Era era) => + TxOut era -> + (Addr (Crypto era), Core.Value era, StrictMaybe (DataHash (Crypto era))) +viewCompactTxOut (TxOutCompact bs c dh) = (addr, val, dh) + where + addr = decompactAddr bs + val = fromCompact c + instance - ( Show (Core.Value era) + ( Era era, + Show (Core.Value era), + Show (CompactForm (Core.Value era)) ) => Show (TxOut era) where - show = error "Not yet implemented" + show = show . viewCompactTxOut deriving via InspectHeapNamed "TxOut" (TxOut era) instance NoThunks (TxOut era) @@ -210,7 +222,10 @@ instance NoThunks (TxBodyRaw era) deriving instance - (Era era, Show (Core.Value era), Show (PParamsDelta era)) => + ( Era era, + Show (Core.Value era), + Show (PParamsDelta era) + ) => Show (TxBodyRaw era) newtype TxBody era = TxBodyConstr (MemoBytes (TxBodyRaw era)) @@ -483,7 +498,7 @@ encodeTxBodyRaw fromSJust :: StrictMaybe a -> a fromSJust (SJust x) = x - fromSJust SNothing = error "SNothing in fromSJust" + fromSJust SNothing = error "SNothing in fromSJust. This should never happen, it is guarded by isSNothing" instance forall era. diff --git a/alonzo/impl/test/test/Test/Cardano/Ledger/Alonzo/Serialisation/Tripping.hs b/alonzo/impl/test/test/Test/Cardano/Ledger/Alonzo/Serialisation/Tripping.hs index 017af47f705..aa00e98c2dc 100644 --- a/alonzo/impl/test/test/Test/Cardano/Ledger/Alonzo/Serialisation/Tripping.hs +++ b/alonzo/impl/test/test/Test/Cardano/Ledger/Alonzo/Serialisation/Tripping.hs @@ -1,12 +1,13 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} module Test.Cardano.Ledger.Alonzo.Serialisation.Tripping where import Cardano.Binary import Cardano.Ledger.Alonzo (AlonzoEra) -import Cardano.Ledger.Alonzo.Data (AuxiliaryData, Data) +import Cardano.Ledger.Alonzo.Data (AuxiliaryData, Data (..)) import Cardano.Ledger.Alonzo.PParams (PParams, PParamsUpdate) import Cardano.Ledger.Alonzo.Rules.Utxo (UtxoPredicateFailure) import Cardano.Ledger.Alonzo.Rules.Utxos (UtxosPredicateFailure) @@ -16,8 +17,10 @@ import Cardano.Ledger.Alonzo.Scripts (Script) import Cardano.Ledger.Alonzo.Tx (CostModel, WitnessPPData) import Cardano.Ledger.Alonzo.TxBody (TxBody) import Cardano.Ledger.Alonzo.TxWitness +import qualified Data.ByteString as BS (ByteString) import qualified Data.ByteString.Base16.Lazy as Base16 import qualified Data.ByteString.Lazy.Char8 as BSL +import qualified Language.PlutusTx as Plutus import Shelley.Spec.Ledger.Metadata (Metadata) import Test.Cardano.Ledger.Alonzo.Serialisation.Generators () import Test.Cardano.Ledger.ShelleyMA.Serialisation.Coders (roundTrip, roundTripAnn) @@ -64,6 +67,15 @@ trippingAnn x = trippingF roundTripAnn x tripping :: (Eq src, Show src, ToCBOR src, FromCBOR src) => src -> Property tripping x = trippingF roundTrip x +-- ========================== +-- Catch violations ofbytestrings that are toolong. + +toolong :: BS.ByteString +toolong = "1234567890-=`~@#$%^&*()_+qwertyuiopQWERTYUIOPasdfghjklASDFGHJKLzxcvbnmZXCVBNM" + +badData :: Data (AlonzoEra C_Crypto) +badData = Data $ Plutus.List [Plutus.I 34, Plutus.B toolong] + tests :: TestTree tests = testGroup @@ -72,6 +84,7 @@ tests = trippingAnn @(Script (AlonzoEra C_Crypto)), testProperty "alonzo/Data" $ trippingAnn @(Data (AlonzoEra C_Crypto)), + testProperty "alonzo/Data/CatchToolong" (expectFailure (trippingAnn badData)), testProperty "alonzo/Metadata" $ trippingAnn @(Metadata (AlonzoEra C_Crypto)), testProperty "alonzo/TxWitness" $ diff --git a/cardano-ledger-test/bench/Bench/Cardano/Ledger/ApplyTx.hs b/cardano-ledger-test/bench/Bench/Cardano/Ledger/ApplyTx.hs index 9dead96a367..a8088f088ce 100644 --- a/cardano-ledger-test/bench/Bench/Cardano/Ledger/ApplyTx.hs +++ b/cardano-ledger-test/bench/Bench/Cardano/Ledger/ApplyTx.hs @@ -5,6 +5,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} -- | Benchmarks for transaction application module Bench.Cardano.Ledger.ApplyTx (applyTxBenchmarks) where @@ -12,7 +13,7 @@ module Bench.Cardano.Ledger.ApplyTx (applyTxBenchmarks) where import Cardano.Binary import Cardano.Ledger.Allegra (AllegraEra) import qualified Cardano.Ledger.Core as Core -import Cardano.Ledger.Era (Era) +import Cardano.Ledger.Era (Era, ValidateScript) import Cardano.Ledger.Mary (MaryEra) import Cardano.Ledger.Shelley (ShelleyEra) import Control.DeepSeq (NFData (..)) @@ -34,7 +35,6 @@ import Shelley.Spec.Ledger.API Tx, applyTxsTransition, ) -import Shelley.Spec.Ledger.PParams (PParams' (..)) import Shelley.Spec.Ledger.Slot (SlotNo (SlotNo)) import Test.Shelley.Spec.Ledger.ConcreteCryptoTypes (C_Crypto) import Test.Shelley.Spec.Ledger.Utils (testGlobals) @@ -140,7 +140,10 @@ applyTxGroup = deserialiseTxEra :: forall era. ( Era era, - ApplyTx era + ValidateScript era, + FromCBOR (Annotator (Core.TxBody era)), + FromCBOR (Annotator (Core.AuxiliaryData era)), + FromCBOR (Annotator (Core.Witnesses era)) ) => Proxy era -> Benchmark diff --git a/semantics/executable-spec/src/Data/Coders.hs b/semantics/executable-spec/src/Data/Coders.hs index 5d34c0281c7..edb89ca903b 100644 --- a/semantics/executable-spec/src/Data/Coders.hs +++ b/semantics/executable-spec/src/Data/Coders.hs @@ -34,6 +34,7 @@ module Data.Coders (!>), ( Decode w (Annotator t) ApplyAnn :: Decode w1 (Annotator (a -> t)) -> Decode ('Closed d) (Annotator a) -> Decode w1 (Annotator t) + -- A function to Either can raise an error when applied by returning (Left errorMessage) + ApplyErr :: Decode w1 (a -> Either String t) -> Decode ('Closed d) a -> Decode w1 t infixl 4 t) -> Decode ('Closed w) a -> Decode w1 t x t)) -> Decode ('Closed d) (Annotator a) -> Decode w1 (Annotator t) x <*! y = ApplyAnn x y +( Either String t) -> Decode ('Closed d) a -> Decode w1 t +f Int hsize (Summands _ _) = 1 hsize (SumD _) = 0 @@ -548,6 +556,7 @@ hsize (SparseKeyed _ _ _ _) = 1 hsize (TagD _ _) = 1 hsize (Ann x) = hsize x hsize (ApplyAnn f x) = hsize f + hsize x +hsize (ApplyErr f x) = hsize f + hsize x decode :: Decode w t -> Decoder s t decode x = fmap snd (decodE x) @@ -580,6 +589,12 @@ decodeCount (ApplyD cn g) n = do (i, f) <- decodeCount cn (n + hsize g) y <- decodeClosed g pure (i, f y) +decodeCount (ApplyErr cn g) n = do + (i, f) <- decodeCount cn (n + hsize g) + y <- decodeClosed g + case f y of + Right z -> pure(i,z) + Left message -> cborError $ DecoderErrorCustom "decoding error:" (Text.pack $ message) -- The type of DecodeClosed precludes pattern match against (SumD c) as the types are different. @@ -607,6 +622,12 @@ decodeClosed (ApplyAnn g x) = do f <- decodeClosed g y <- decodeClosed x pure (f <*> y) +decodeClosed (ApplyErr cn g) = do + f <- decodeClosed cn + y <- decodeClosed g + case f y of + Right z -> pure z + Left message -> cborError $ DecoderErrorCustom "decoding error:" (Text.pack $ message) decodeSparse :: Typeable a => diff --git a/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/API/Mempool.hs b/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/API/Mempool.hs index a69e697e91d..c2c5d3236e3 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/API/Mempool.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/API/Mempool.hs @@ -51,12 +51,11 @@ import Shelley.Spec.Ledger.PParams (PParams' (..)) import Shelley.Spec.Ledger.STS.Ledgers (LedgersEnv, LedgersPredicateFailure) import qualified Shelley.Spec.Ledger.STS.Ledgers as Ledgers import Shelley.Spec.Ledger.Slot (SlotNo) -import Shelley.Spec.Ledger.Tx (Tx) -- TODO #1304: add reapplyTxs class - ( ChainData (Tx era), - AnnotatedData (Tx era), + ( ChainData (Core.Tx era), + AnnotatedData (Core.Tx era), Eq (ApplyTxError era), Show (ApplyTxError era), Typeable (ApplyTxError era), @@ -65,7 +64,7 @@ class BaseM (Core.EraRule "LEDGERS" era) ~ ShelleyBase, Environment (Core.EraRule "LEDGERS" era) ~ LedgersEnv era, State (Core.EraRule "LEDGERS" era) ~ MempoolState era, - Signal (Core.EraRule "LEDGERS" era) ~ Seq (Tx era), + Signal (Core.EraRule "LEDGERS" era) ~ Seq (Core.Tx era), PredicateFailure (Core.EraRule "LEDGERS" era) ~ LedgersPredicateFailure era ) => ApplyTx era @@ -74,14 +73,14 @@ class MonadError (ApplyTxError era) m => Globals -> SlotNo -> - Seq (Tx era) -> + Seq (Core.Tx era) -> NewEpochState era -> m (NewEpochState era) default applyTxs :: (MonadError (ApplyTxError era) m) => Globals -> SlotNo -> - Seq (Tx era) -> + Seq (Core.Tx era) -> NewEpochState era -> m (NewEpochState era) applyTxs globals slot txs state = @@ -164,13 +163,13 @@ applyTxsTransition :: BaseM (Core.EraRule "LEDGERS" era) ~ ShelleyBase, Environment (Core.EraRule "LEDGERS" era) ~ LedgersEnv era, State (Core.EraRule "LEDGERS" era) ~ MempoolState era, - Signal (Core.EraRule "LEDGERS" era) ~ Seq (Tx era), + Signal (Core.EraRule "LEDGERS" era) ~ Seq (Core.Tx era), PredicateFailure (Core.EraRule "LEDGERS" era) ~ LedgersPredicateFailure era, MonadError (ApplyTxError era) m ) => Globals -> MempoolEnv era -> - Seq (Tx era) -> + Seq (Core.Tx era) -> MempoolState era -> m (MempoolState era) applyTxsTransition globals env txs state = diff --git a/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/CompactAddr.hs b/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/CompactAddr.hs index dc029f08fcc..31799901644 100644 --- a/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/CompactAddr.hs +++ b/shelley/chain-and-ledger/executable-spec/src/Shelley/Spec/Ledger/CompactAddr.hs @@ -46,6 +46,9 @@ import Shelley.Spec.Ledger.Slot (SlotNo (..)) newtype CompactAddr crypto = UnsafeCompactAddr ShortByteString deriving (Eq, Ord) +instance CC.Crypto c => Show (CompactAddr c) where + show c = show (decompactAddr c) + compactAddr :: Addr crypto -> CompactAddr crypto compactAddr = UnsafeCompactAddr . SBS.toShort . serialiseAddr diff --git a/shelley/chain-and-ledger/shelley-spec-ledger-test/shelley-spec-ledger-test.cabal b/shelley/chain-and-ledger/shelley-spec-ledger-test/shelley-spec-ledger-test.cabal index 44715c83837..20ce55dc908 100644 --- a/shelley/chain-and-ledger/shelley-spec-ledger-test/shelley-spec-ledger-test.cabal +++ b/shelley/chain-and-ledger/shelley-spec-ledger-test/shelley-spec-ledger-test.cabal @@ -71,6 +71,7 @@ library Test.Shelley.Spec.Ledger.Shrinkers Test.Shelley.Spec.Ledger.Utils Test.Shelley.Spec.Ledger.PropertyTests + Test.Shelley.Spec.Ledger.Rules.TestChain Test.TestScenario other-modules: Test.Shelley.Spec.Ledger.Address.Bootstrap @@ -78,7 +79,6 @@ library Test.Shelley.Spec.Ledger.ByronTranslation Test.Shelley.Spec.Ledger.Examples.Federation Test.Shelley.Spec.Ledger.Rules.ClassifyTraces - Test.Shelley.Spec.Ledger.Rules.TestChain Test.Shelley.Spec.Ledger.Rules.TestDeleg Test.Shelley.Spec.Ledger.Rules.TestPool Test.Shelley.Spec.Ledger.Rules.TestPoolreap diff --git a/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rewards.hs b/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rewards.hs index d45b843dbc2..df015300d53 100644 --- a/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rewards.hs +++ b/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rewards.hs @@ -9,16 +9,13 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module Test.Shelley.Spec.Ledger.Rewards (rewardTests, C, defaultMain) where +module Test.Shelley.Spec.Ledger.Rewards (rewardTests, C, defaultMain, newEpochProp) where import Cardano.Binary (toCBOR) import qualified Cardano.Crypto.DSIGN as Crypto import Cardano.Crypto.Hash (MD5, hashToBytes) import Cardano.Crypto.Seed (mkSeedFromBytes) import qualified Cardano.Crypto.VRF as Crypto --- Arbitrary(NewEpochState era) --- instance (EraGen (ShelleyEra C)) - import Cardano.Ledger.Coin (Coin (..), DeltaCoin (..), rationalToCoinViaFloor, toDeltaCoin) import qualified Cardano.Ledger.Core as Core import Cardano.Ledger.Crypto (VRF) @@ -125,7 +122,7 @@ import Test.Shelley.Spec.Ledger.Utils testGlobals, unsafeMkUnitInterval, ) -import Test.Tasty (TestTree, defaultMain, testGroup) +import Test.Tasty -- (TestTree, defaultMain, testGroup) import Test.Tasty.HUnit (testCaseInfo) import Test.Tasty.QuickCheck ( Gen, @@ -138,7 +135,12 @@ import Test.Tasty.QuickCheck property, testProperty, withMaxSuccess, + (===), ) +import Test.Shelley.Spec.Ledger.Rules.TestChain(forAllChainTrace) +import Control.State.Transition.Trace(SourceSignalTarget (..), sourceSignalTargets) +import Shelley.Spec.Ledger.STS.Chain (ChainState (..)) +import Cardano.Ledger.Pretty(PrettyA(..)) -- ======================================================================== -- Bounds and Constants -- @@ -422,8 +424,8 @@ sameWithOrWithoutProvenance :: (Core.PParams era ~ PParams era) => Globals -> NewEpochState era -> - Bool -sameWithOrWithoutProvenance globals newepochstate = with == without + Property +sameWithOrWithoutProvenance globals newepochstate = with === without where (with, _) = getRewardInfo globals newepochstate without = justRewardInfo globals newepochstate @@ -432,8 +434,9 @@ nothingInNothingOut :: forall era. (Core.PParams era ~ PParams era) => NewEpochState era -> - Bool + Property nothingInNothingOut newepochstate = + counterexample "nothingInNothingOut fails" $ runReader (preservesNothing $ createRUpd slotsPerEpoch blocksmade epochstate maxsupply asc k) globals @@ -454,8 +457,9 @@ justInJustOut :: forall era. (Core.PParams era ~ PParams era) => NewEpochState era -> - Bool + Property justInJustOut newepochstate = + counterexample "justInJustOut fails" $ runReader (preservesJust def $ createRUpd slotsPerEpoch blocksmade epochstate maxsupply asc k) globals @@ -541,9 +545,10 @@ rewardOnePool else Map.insert potentialRewards = f (getRwdCred $ _poolRAcnt pool) lReward mRewards - rewards' = Map.filter (/= Coin 0) $ eval (addrsRew ◁ potentialRewards) + rewards' = Map.filter (/= Coin 0) $ (eval (addrsRew ◁ potentialRewards)) + -rewardOld :: +rewardOld :: forall era. PParams era -> BlocksMade (Crypto era) -> Coin -> @@ -573,6 +578,7 @@ rewardOld where totalBlocks = sum b Coin activeStake = fold . unStake $ stake + results :: [(KeyHash 'StakePool (Crypto era),Maybe (Map (Credential 'Staking (Crypto era)) Coin),Likelihood)] results = do (hk, pparams) <- Map.toList poolParams let sigma = if totalStake == 0 then 0 else fromIntegral pstake % fromIntegral totalStake @@ -605,7 +611,7 @@ rewardOld if HardForks.aggregatedRewards pp then Map.unionsWith (<>) else Map.unions - rewards' = f . catMaybes $ fmap (\(_, x, _) -> x) results + rewards' = f . catMaybes $ fmap (\ (_, x, _) -> x) results hs = Map.fromList $ fmap (\(hk, _, l) -> (hk, l)) results data RewardUpdateOld crypto = RewardUpdateOld @@ -673,8 +679,11 @@ createRUpdOld slotsPerEpoch b@(BlocksMade b') es@(EpochState acnt ss ls pr _ nm) nonMyopicOld = (updateNonMyopic nm _R newLikelihoods) } -oldEqualsNew :: forall era. (Core.PParams era ~ PParams era) => NewEpochState era -> Bool -oldEqualsNew newepochstate = old == new +oldEqualsNew :: forall era. + ( era ~ C, + Core.PParams era ~ PParams era + ) => NewEpochState era -> Property +oldEqualsNew newepochstate = counterexample (show(prettyA newepochstate)++"\n new = "++show new++"\n old = "++show old) (old===new) where globals = testGlobals epochstate = nesEs newepochstate @@ -686,14 +695,15 @@ oldEqualsNew newepochstate = old == new slotsPerEpoch :: EpochSize slotsPerEpoch = runReader (epochInfoSize (epochInfo globals) epochnumber) globals unAggregated = runReader (runProvM $ createRUpd slotsPerEpoch blocksmade epochstate maxsupply asc k) globals + old :: Map (Credential 'Staking (Crypto era)) Coin old = rsOld $ runReader (createRUpdOld slotsPerEpoch blocksmade epochstate maxsupply) globals new_with_zeros = aggregateRewards @(Crypto era) (emptyPParams {_protocolVersion = ProtVer 2 0}) (rs unAggregated) new = Map.filter (/= Coin 0) new_with_zeros asc = activeSlotCoeff globals k = securityParameter testGlobals -oldEqualsNewOn :: forall era. (Core.PParams era ~ PParams era) => NewEpochState era -> Bool -oldEqualsNewOn newepochstate = old == new +oldEqualsNewOn :: forall era. (Core.PParams era ~ PParams era) => NewEpochState era -> Property +oldEqualsNewOn newepochstate = old === new where globals = testGlobals epochstate = nesEs newepochstate @@ -705,12 +715,28 @@ oldEqualsNewOn newepochstate = old == new slotsPerEpoch :: EpochSize slotsPerEpoch = runReader (epochInfoSize (epochInfo globals) epochnumber) globals (unAggregated, _) = runReader (runWithProvM def $ createRUpd slotsPerEpoch blocksmade epochstate maxsupply asc k) globals + old :: Map (Credential 'Staking (Crypto era)) Coin old = rsOld $ runReader (createRUpdOld slotsPerEpoch blocksmade epochstate maxsupply) globals new_with_zeros = aggregateRewards @(Crypto era) (emptyPParams {_protocolVersion = ProtVer 2 0}) (rs unAggregated) new = Map.filter (/= Coin 0) new_with_zeros asc = activeSlotCoeff globals k = securityParameter testGlobals + +lastElem :: [a] -> Maybe a +lastElem [a] = Just a +lastElem [] = Nothing +lastElem (_ : xs) = lastElem xs + +-- | Provide a legitimate NewEpochState to make an test Property +newEpochProp :: Word64 -> (NewEpochState C -> Property) -> Property +newEpochProp tracelen propf = withMaxSuccess 100 $ + forAllChainTrace @C tracelen $ \tr -> + case (lastElem (sourceSignalTargets tr)) of + Just(SourceSignalTarget {target}) -> propf (chainNes target) + _ -> True === True + + -- ================================================================ reward :: @@ -762,17 +788,18 @@ rewardPulser -- ================================================================== +chainlen :: Word64 +chainlen = 20 -- 50 -- 43 -- 37 -- 25 -- 50 -- 100 + rewardTests :: TestTree rewardTests = testGroup "Reward Tests" - [ testProperty - "Sum of rewards is bounded by reward pot" - (withMaxSuccess numberOfTests (rewardsBoundedByPot (Proxy @C))), - testProperty "provenance does not affect result" (sameWithOrWithoutProvenance @C testGlobals), - testProperty "ProvM preserves Nothing" (nothingInNothingOut @C), - testProperty "ProvM preserves Just" (justInJustOut @C), - testProperty "oldstyle (aggregate immediately) matches newstyle (late aggregation) with provenance off style" (oldEqualsNew @C), - testProperty "oldstyle (aggregate immediately) matches newstyle (late aggregation) with provenance on style" (oldEqualsNewOn @C), + [ testProperty "Sum of rewards is bounded by reward pot" (withMaxSuccess numberOfTests (rewardsBoundedByPot (Proxy @C))), + testProperty "provenance does not affect result" (newEpochProp 100 (sameWithOrWithoutProvenance @C testGlobals)), + testProperty "ProvM preserves Nothing" (newEpochProp 100 (nothingInNothingOut @C)), + testProperty "ProvM preserves Just" (newEpochProp 100 (justInJustOut @C)), + testProperty "oldstyle (aggregate immediately) matches newstyle (late aggregation) with provenance off style" (newEpochProp chainlen (oldEqualsNew @C)) , + testProperty "oldstyle (aggregate immediately) matches newstyle (late aggregation) with provenance on style" (newEpochProp chainlen (oldEqualsNewOn @C)), testCaseInfo "Reward Provenance works" (rewardsProvenance (Proxy @C)) ] diff --git a/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rules/TestChain.hs b/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rules/TestChain.hs index bbd43ff88a6..fdcdbafe115 100644 --- a/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rules/TestChain.hs +++ b/shelley/chain-and-ledger/shelley-spec-ledger-test/test/Test/Shelley/Spec/Ledger/Rules/TestChain.hs @@ -18,6 +18,7 @@ module Test.Shelley.Spec.Ledger.Rules.TestChain poolProperties, -- Test Delegation delegProperties, + forAllChainTrace, ) where