From aee8649b2613b70c80bab482137a0218ba22f021 Mon Sep 17 00:00:00 2001 From: Luke Nadur <19835357+intricate@users.noreply.github.com> Date: Tue, 11 Jun 2019 17:13:58 -0500 Subject: [PATCH] [#526] Add tests for multiple validation modes --- cardano-ledger/cardano-ledger.cabal | 3 + .../Cardano/Chain/Block/ValidationMode.hs | 268 ++++++++++++++++++ .../test/Test/Cardano/Chain/Common/Gen.hs | 13 +- .../Test/Cardano/Chain/Elaboration/Block.hs | 4 +- .../Test/Cardano/Chain/Elaboration/UTxO.hs | 1 + .../Test/Cardano/Chain/Elaboration/Update.hs | 49 ++++ .../Test/Cardano/Chain/UTxO/ValidationMode.hs | 230 +++++++++++++++ cardano-ledger/test/test.hs | 4 + crypto/test/Test/Cardano/Crypto/Gen.hs | 1 + 9 files changed, 565 insertions(+), 8 deletions(-) create mode 100644 cardano-ledger/test/Test/Cardano/Chain/Block/ValidationMode.hs create mode 100644 cardano-ledger/test/Test/Cardano/Chain/Elaboration/Update.hs create mode 100644 cardano-ledger/test/Test/Cardano/Chain/UTxO/ValidationMode.hs diff --git a/cardano-ledger/cardano-ledger.cabal b/cardano-ledger/cardano-ledger.cabal index e4da18ef..ed480ff1 100644 --- a/cardano-ledger/cardano-ledger.cabal +++ b/cardano-ledger/cardano-ledger.cabal @@ -175,6 +175,7 @@ test-suite cardano-ledger-test Test.Cardano.Chain.Block.Gen Test.Cardano.Chain.Block.Model Test.Cardano.Chain.Block.Validation + Test.Cardano.Chain.Block.ValidationMode Test.Cardano.Chain.Common.Address Test.Cardano.Chain.Common.CBOR @@ -194,6 +195,7 @@ test-suite cardano-ledger-test Test.Cardano.Chain.Elaboration.Block Test.Cardano.Chain.Elaboration.Delegation Test.Cardano.Chain.Elaboration.Keys + Test.Cardano.Chain.Elaboration.Update Test.Cardano.Chain.Elaboration.UTxO Test.Cardano.Chain.Epoch.File @@ -217,6 +219,7 @@ test-suite cardano-ledger-test Test.Cardano.Chain.UTxO.Gen Test.Cardano.Chain.UTxO.Json Test.Cardano.Chain.UTxO.Model + Test.Cardano.Chain.UTxO.ValidationMode Test.Cardano.Chain.Update.CBOR Test.Cardano.Chain.Update.Example diff --git a/cardano-ledger/test/Test/Cardano/Chain/Block/ValidationMode.hs b/cardano-ledger/test/Test/Cardano/Chain/Block/ValidationMode.hs new file mode 100644 index 00000000..970a6f34 --- /dev/null +++ b/cardano-ledger/test/Test/Cardano/Chain/Block/ValidationMode.hs @@ -0,0 +1,268 @@ +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} + +module Test.Cardano.Chain.Block.ValidationMode + ( tests + ) +where + +import Cardano.Prelude hiding (State) +import Test.Cardano.Prelude + +import Control.Lens ((^.)) +import qualified Data.Bimap as BM +import qualified Data.Map.Strict as M +import qualified Data.Sequence as Seq +import qualified Data.Set as S + +import Cardano.Binary (Annotated (..)) +import Cardano.Chain.Block + ( ABlock (..) + , AHeader (..) + , BlockValidationMode (..) + , Proof (..) + , blockProof + , initialChainValidationState + , updateBlock + ) +import Cardano.Chain.Delegation as Delegation +import Cardano.Chain.UTxO (TxProof) +import Cardano.Crypto (Hash) + +import Hedgehog +import qualified Hedgehog.Gen as Gen +import qualified Hedgehog.Range as Range + +import qualified Cardano.Spec.Chain.STS.Block as Abstract +import qualified Cardano.Spec.Chain.STS.Rule.Chain as Abstract +import Cardano.Spec.Chain.STS.Rule.Chain (CHAIN) +import Cardano.Ledger.Spec.STS.UTXOWS (UTXOWS) +import Cardano.Ledger.Spec.STS.UTXO (UTxOEnv (..), UTxOState (..)) +import Control.State.Transition +import Control.State.Transition.Generator +import qualified Ledger.Core as Abstract +import Ledger.Delegation + ( ADELEGS + , DELEG + , DIState (..) + , DSEnv (..) + , DState (..) + ) +import Ledger.GlobalParams (lovelaceCap) +import qualified Ledger.Update as Abstract +import qualified Ledger.UTxO as Abstract + +import Test.Cardano.Chain.Block.Model (elaborateAndUpdate) +import qualified Test.Cardano.Chain.Delegation.Gen as Delegation +import Test.Cardano.Chain.Elaboration.Block (abEnvToCfg, elaborateBS, rcDCert) +import qualified Test.Cardano.Chain.Update.Gen as Update +import Test.Cardano.Chain.UTxO.Gen (genTxProof) +import Test.Cardano.Chain.UTxO.Model (elaborateInitialUTxO) +import Test.Cardano.Crypto.Gen (feedPM, genAbstractHash) +import Test.Options (TSGroup, TSProperty, withTestsTS) + +-------------------------------------------------------------------------------- +-- BlockValidationMode Properties +-------------------------------------------------------------------------------- + +-- | Property: When calling 'updateBlock' given a valid 'Block', validation +-- should pass in all 'BlockValidationMode's. +ts_prop_updateBlock_Valid :: TSProperty +ts_prop_updateBlock_Valid = + withTestsTS 100 + . property + $ do + chainEnv@(_, abstractInitialUTxO, _, _) <- forAll $ initEnvGen @CHAIN + chainState <- forAll $ genInitialChainState chainEnv + abstractBlock <- forAll $ + Abstract.sigGenChain + Abstract.NoGenDelegation + Abstract.NoGenUTxO + chainEnv + chainState + let config = abEnvToCfg chainEnv + cvs = either (panic . show) (\a -> a) (initialChainValidationState config) + (_, txIdMap) = elaborateInitialUTxO abstractInitialUTxO + bvmode <- forAll $ genBlockValidationMode + case elaborateAndUpdate bvmode config (cvs, txIdMap) (chainState, abstractBlock) of + Left _ -> failure + Right _ -> success + +-- | Property: When calling 'updateBlock' given a 'Block' with an invalid +-- 'Proof', 'Block' validation should only pass in the 'NoBlockValidation' mode. +-- This is because this mode does not perform any validation on the 'Block'. +ts_prop_updateBlock_InvalidProof :: TSProperty +ts_prop_updateBlock_InvalidProof = + withTestsTS 100 + . property + $ do + chainEnv@(_, abstractInitialUTxO, _, _) <- forAll $ initEnvGen @CHAIN + chainState <- forAll $ genInitialChainState chainEnv + abstractBlock <- forAll $ + Abstract.sigGenChain + Abstract.NoGenDelegation + Abstract.NoGenUTxO + chainEnv + chainState + let config = abEnvToCfg chainEnv + cvs = either (panic . show) (\a -> a) (initialChainValidationState config) + (_, txIdMap) = elaborateInitialUTxO abstractInitialUTxO + dCert = rcDCert (abstractBlock ^. Abstract.bHeader . Abstract.bhIssuer) chainState + bvmode <- forAll $ genBlockValidationMode + let (concreteBlock, _txIdMap') = elaborateBS txIdMap config dCert cvs abstractBlock + annotateShow concreteBlock + invalidBlock <- forAll $ invalidateABlockProof concreteBlock + case updateBlock bvmode config cvs invalidBlock of + Left _ -> + if bvmode == BlockValidation + then success + else failure + Right _ -> + if bvmode == NoBlockValidation + then success + else failure + +-------------------------------------------------------------------------------- +-- Generators +-------------------------------------------------------------------------------- + +genInitialChainState + :: Environment CHAIN + -> Gen (State CHAIN) +genInitialChainState env = do + let (_slot, utxo0', _dsenv, pps') = env + utxoEnv = UTxOEnv { utxo0 = utxo0', pps = pps' } + s0 = Abstract.Slot 0 + utxoSt0 = createInitialUTxOState utxoEnv + initialDelegEnv <- initEnvGen @DELEG + let initialADelegsEnv = _dSEnvAllowedDelegators initialDelegEnv + let ds = createInitialDIState (createInitialDState initialADelegsEnv) + pure $! ( s0 + , (Seq.fromList . BM.keys . _dIStateDelegationMap) ds + , Abstract.genesisHash + , utxoSt0 + , ds + , Abstract.emptyUPIState + ) + +genHash :: Gen Abstract.Hash +genHash = Abstract.Hash <$> Gen.int Range.constantBounded + +genBlockValidationMode :: Gen BlockValidationMode +genBlockValidationMode = Gen.element [BlockValidation, NoBlockValidation] + +-------------------------------------------------------------------------------- +-- Helpers +-------------------------------------------------------------------------------- + +createInitialUTxOState + :: Environment UTXOWS + -> State UTXOWS +createInitialUTxOState utxoEnv = + UTxOState{ utxo = utxo0, reserves = lovelaceCap - Abstract.balance utxo0 } + where + UTxOEnv + { utxo0 + } = utxoEnv + +createInitialDState + :: Environment ADELEGS + -> State ADELEGS +createInitialDState env = + DState + { _dStateDelegationMap = BM.fromList $ + map (\vkg@(Abstract.VKeyGenesis key) -> (vkg, key)) + (S.toList env) + , _dStateLastDelegation = M.fromSet (const (Abstract.Slot 0)) env + } + +createInitialDIState + :: State ADELEGS + -> State DELEG +createInitialDIState dState = + DIState + { _dIStateDelegationMap = _dStateDelegationMap dState + , _dIStateLastDelegation = _dStateLastDelegation dState + , _dIStateScheduledDelegations = [] + , _dIStateKeyEpochDelegations = S.empty + } + +modifyAHeader + :: (AHeader ByteString -> AHeader ByteString) + -> ABlock ByteString + -> ABlock ByteString +modifyAHeader ahModifier ab = + ab { blockHeader = ahModifier (blockHeader ab) } + +modifyAProof + :: (Annotated Proof ByteString -> Annotated Proof ByteString) + -> ABlock ByteString + -> ABlock ByteString +modifyAProof apModifier ab = + modifyAHeader ahModifier ab + where + ahModifier :: AHeader ByteString -> AHeader ByteString + ahModifier ah = ah { aHeaderProof = apModifier (aHeaderProof ah) } + +modifyDelegationProof + :: (Hash Delegation.Payload -> Hash Delegation.Payload) + -> ABlock ByteString + -> ABlock ByteString +modifyDelegationProof dpModifier ab = + modifyAProof apModifier ab + where + apModifier :: Annotated Proof ByteString -> Annotated Proof ByteString + apModifier (Annotated p bs) = Annotated + p { proofDelegation = dpModifier (proofDelegation p) } + bs + +modifyTxProof + :: (TxProof -> TxProof) + -> ABlock ByteString + -> ABlock ByteString +modifyTxProof tpModifier ab = + modifyAProof apModifier ab + where + apModifier :: Annotated Proof ByteString -> Annotated Proof ByteString + apModifier (Annotated p bs) = Annotated + p { proofUTxO = tpModifier (proofUTxO p) } + bs + +invalidateABlockProof + :: ABlock ByteString + -> Gen (ABlock ByteString) +invalidateABlockProof ab = + -- 'Gen.filter' to ensure we don't generate a valid proof + Gen.filter (\x -> blockProof x /= blockProof ab) $ do + txProof <- Gen.choice + [ pure $ (proofUTxO . blockProof) ab + , feedPM genTxProof + ] + dlgProof <- Gen.choice + [ pure $ (proofDelegation . blockProof) ab + , genAbstractHash (feedPM Delegation.genPayload) + ] + updProof <- Gen.choice + [ pure $ proofUpdate (blockProof ab) + , feedPM Update.genProof + ] + pure $ modifyAProof + (\(Annotated p bs) -> Annotated + (p + { proofUTxO = txProof + , proofDelegation = dlgProof + , proofUpdate = updProof + } + ) + bs + ) + ab + +-------------------------------------------------------------------------------- +-- Main Test Export +-------------------------------------------------------------------------------- + +tests :: TSGroup +tests = $$discoverPropArg diff --git a/cardano-ledger/test/Test/Cardano/Chain/Common/Gen.hs b/cardano-ledger/test/Test/Cardano/Chain/Common/Gen.hs index 05bd6ea4..283b2b0d 100644 --- a/cardano-ledger/test/Test/Cardano/Chain/Common/Gen.hs +++ b/cardano-ledger/test/Test/Cardano/Chain/Common/Gen.hs @@ -16,6 +16,7 @@ module Test.Cardano.Chain.Common.Gen , genCompactAddress , genCustomLovelace , genLovelace + , genLovelaceWithRange , genLovelacePortion , genMerkleRoot , genMerkleTree @@ -124,14 +125,14 @@ genCompactAddress :: Gen CompactAddress genCompactAddress = toCompactAddress <$> genAddress genCustomLovelace :: Word64 -> Gen Lovelace -genCustomLovelace size = - mkLovelace <$> Gen.word64 (Range.linear 0 size) >>= \case - Right lovelace -> pure lovelace - Left err -> panic $ sformat build err +genCustomLovelace size = genLovelaceWithRange (Range.linear 0 size) genLovelace :: Gen Lovelace -genLovelace = - mkLovelace <$> Gen.word64 (Range.constant 0 maxLovelaceVal) >>= \case +genLovelace = genLovelaceWithRange (Range.constant 0 maxLovelaceVal) + +genLovelaceWithRange :: Range Word64 -> Gen Lovelace +genLovelaceWithRange r = + mkLovelace <$> Gen.word64 r >>= \case Right lovelace -> pure lovelace Left err -> panic $ sformat ("The impossible happened in genLovelace: " . build) err diff --git a/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Block.hs b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Block.hs index 02354c27..259f7b8b 100644 --- a/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Block.hs +++ b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Block.hs @@ -216,8 +216,8 @@ abEnvToCfg (_, _, dsEnv, pps) = gPps = Update.ProtocolParameters { Update.ppScriptVersion = 0 , Update.ppSlotDuration = 0 - , Update.ppMaxBlockSize = 748 * pps ^. maxBkSz - , Update.ppMaxHeaderSize = 95 * pps ^. maxHdrSz + , Update.ppMaxBlockSize = 832 * pps ^. maxBkSz + , Update.ppMaxHeaderSize = 569 * pps ^. maxHdrSz , Update.ppMaxTxSize = 318 * pps ^. maxTxSz , Update.ppMaxProposalSize = 0 , Update.ppMpcThd = LovelacePortion 0 diff --git a/cardano-ledger/test/Test/Cardano/Chain/Elaboration/UTxO.hs b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/UTxO.hs index df1db311..020f298e 100644 --- a/cardano-ledger/test/Test/Cardano/Chain/Elaboration/UTxO.hs +++ b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/UTxO.hs @@ -7,6 +7,7 @@ module Test.Cardano.Chain.Elaboration.UTxO ( elaborateUTxOEnv , elaborateUTxO + , elaborateTx , elaborateTxWitsBS , elaborateTxOut ) diff --git a/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Update.hs b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Update.hs new file mode 100644 index 00000000..534ef098 --- /dev/null +++ b/cardano-ledger/test/Test/Cardano/Chain/Elaboration/Update.hs @@ -0,0 +1,49 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Test.Cardano.Chain.Elaboration.Update + ( elaboratePParams + ) +where + +import Cardano.Prelude + +import qualified Cardano.Chain.Common as Concrete +import qualified Cardano.Chain.Slotting as Concrete +import qualified Cardano.Chain.Update as Concrete + +import qualified Ledger.Update as Abstract + +import Test.Cardano.Chain.Genesis.Dummy (dummyProtocolParameters) + +elaboratePParams :: Abstract.PParams -> Concrete.ProtocolParameters +elaboratePParams pps = Concrete.ProtocolParameters + { Concrete.ppScriptVersion = fromIntegral $ Abstract._scriptVersion pps + , Concrete.ppSlotDuration = Concrete.ppSlotDuration dummyProtocolParameters + , Concrete.ppMaxBlockSize = 748 * Abstract._maxBkSz pps + , Concrete.ppMaxHeaderSize = 95 * Abstract._maxHdrSz pps + , Concrete.ppMaxTxSize = 4096 * Abstract._maxTxSz pps + , Concrete.ppMaxProposalSize = 0 + , Concrete.ppMpcThd = Concrete.mkKnownLovelacePortion @0 + , Concrete.ppHeavyDelThd = Concrete.mkKnownLovelacePortion @0 + , Concrete.ppUpdateVoteThd = Concrete.mkKnownLovelacePortion @0 + , Concrete.ppUpdateProposalThd = Concrete.mkKnownLovelacePortion @0 + , Concrete.ppUpdateProposalTTL = 0 + , Concrete.ppSoftforkRule = Concrete.SoftforkRule + (Concrete.mkKnownLovelacePortion @0) + (Concrete.mkKnownLovelacePortion @0) + (Concrete.mkKnownLovelacePortion @0) + , Concrete.ppTxFeePolicy = Concrete.TxFeePolicyTxSizeLinear + (Concrete.TxSizeLinear + (intToLovelace (Abstract._factorA pps)) + (intToLovelace (Abstract._factorB pps)) + ) + , Concrete.ppUnlockStakeEpoch = Concrete.EpochNumber maxBound + } + where + intToLovelace :: Int -> Concrete.Lovelace + intToLovelace x = + case Concrete.mkLovelace (fromIntegral x) of + Left err -> panic $ "intToLovelace: " <> show err + Right l -> l diff --git a/cardano-ledger/test/Test/Cardano/Chain/UTxO/ValidationMode.hs b/cardano-ledger/test/Test/Cardano/Chain/UTxO/ValidationMode.hs new file mode 100644 index 00000000..c9f5466e --- /dev/null +++ b/cardano-ledger/test/Test/Cardano/Chain/UTxO/ValidationMode.hs @@ -0,0 +1,230 @@ +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} + +module Test.Cardano.Chain.UTxO.ValidationMode + ( tests + ) +where + +import Cardano.Prelude +import Test.Cardano.Prelude + +import qualified Data.ByteString as BS +import qualified Data.Map.Strict as M +import qualified Data.Vector as V + +import Cardano.Binary (Annotated (..)) +import Cardano.Chain.Common + ( TxFeePolicy (..) + , calculateTxSizeLinear + , lovelaceToInteger + ) +import Cardano.Chain.Update (ProtocolParameters (..)) +import Cardano.Chain.UTxO + ( ATxAux (..) + , Environment (..) + , TxId + , TxValidationError (..) + , TxValidationMode (..) + , UTxOValidationError (..) + ) +import qualified Cardano.Chain.UTxO as UTxO +import Cardano.Crypto (getProtocolMagicId) + +import Hedgehog +import qualified Hedgehog.Gen as Gen +import qualified Hedgehog.Range as Range + +import qualified Ledger.Core as Abstract +import qualified Ledger.Core.Generators as Abstract +import qualified Ledger.Update as Abstract +import qualified Ledger.Update.Generators as Abstract +import qualified Ledger.UTxO as Abstract +import qualified Ledger.UTxO.Generators as Abstract + +import Test.Cardano.Chain.Elaboration.Update (elaboratePParams) +import Test.Cardano.Chain.Elaboration.UTxO (elaborateTxWitsBS) +import Test.Cardano.Chain.UTxO.Gen (genVKWitness) +import Test.Cardano.Chain.UTxO.Model (elaborateInitialUTxO) +import qualified Test.Cardano.Crypto.Dummy as Dummy +import Test.Options (TSGroup, TSProperty, withTestsTS) + +-------------------------------------------------------------------------------- +-- TxValidationMode Properties +-------------------------------------------------------------------------------- + +-- | Property: When calling 'updateUTxO' given a valid transaction, 'UTxO' +-- validation should pass in all 'TxValidationMode's. +ts_prop_updateUTxO_Valid :: TSProperty +ts_prop_updateUTxO_Valid = + withTestsTS 300 + . property + $ do + -- Generate abstract `PParamsAddrsAndUTxO` + ppau@(PParamsAddrsAndUTxO abstractPparams _ abstractUtxo) <- + forAll $ genPParamsAddrsAndUTxO (Range.constant 1 5) + + -- Elaborate abstract values to concrete. + let pparams = elaboratePParams abstractPparams + (utxo, txIdMap) = elaborateInitialUTxO abstractUtxo + + -- Generate abstract transaction and elaborate. + abstractTxWits <- forAll $ genValidTxWits ppau txIdMap + let tx = elaborateTxWitsBS + (elaborateTxId txIdMap) + abstractTxWits + + -- Validate the generated concrete transaction + let pm = Dummy.aProtocolMagic + env = Environment pm pparams + tvmode <- forAll $ genValidationMode + case UTxO.updateUTxO tvmode env utxo [tx] of + Left _ -> failure + Right _ -> success + +-- | Property: When calling 'updateUTxO' given a valid transaction with an +-- invalid witness, 'UTxO' validation should pass in both the +-- 'TxValidationNoCrypto' and 'NoTxValidation' modes. This is because neither +-- of these modes verify the cryptographic integrity of a transaction. +ts_prop_updateUTxO_InvalidWit :: TSProperty +ts_prop_updateUTxO_InvalidWit = + withTestsTS 300 + . property + $ do + -- Generate abstract `PParamsAddrsAndUTxO` + ppau@(PParamsAddrsAndUTxO abstractPparams _ abstractUtxo) <- + forAll $ genPParamsAddrsAndUTxO (Range.constant 1 5) + + -- Elaborate abstract values to concrete. + let pparams = elaboratePParams abstractPparams + (utxo, txIdMap) = elaborateInitialUTxO abstractUtxo + + -- Generate abstract transaction and elaborate. + abstractTxWits <- forAll $ genValidTxWits ppau txIdMap + let tx = elaborateTxWitsBS + (elaborateTxId txIdMap) + abstractTxWits + + -- Generate an invalid 'TxWitness' and utilize it in the valid + -- transaction generated above. + let pm = Dummy.aProtocolMagic + invalidWitness <- forAll $ + Annotated + <$> (V.fromList + <$> Gen.list (Range.linear 1 10) + (genVKWitness (getProtocolMagicId pm)) + ) + <*> genBytes 32 + let txInvalidWit = tx { aTaWitness = invalidWitness } + + -- Validate the generated concrete transaction + let env = Environment pm pparams + tvmode <- forAll $ genValidationMode + case UTxO.updateUTxO tvmode env utxo [txInvalidWit] of + Left err -> if isInvalidWitnessError err && tvmode == TxValidation + then success + else failure + Right _ -> if tvmode == TxValidation then failure else success + where + isInvalidWitnessError :: UTxOValidationError -> Bool + isInvalidWitnessError (UTxOValidationTxValidationError err) = case err of + TxValidationInvalidWitness _ -> True + _ -> False + isInvalidWitnessError _ = False + +-------------------------------------------------------------------------------- +-- Generators +-------------------------------------------------------------------------------- + +genAbstractAddrs :: Range Int -> Gen [Abstract.Addr] +genAbstractAddrs r = Gen.list r Abstract.addrGen + +genInitialAbstractUTxO :: [Abstract.Addr] -> Gen Abstract.UTxO +genInitialAbstractUTxO addrs = + Abstract.fromTxOuts <$> Abstract.genInitialTxOuts addrs + +genPParamsAddrsAndUTxO + :: Range Int + -- ^ Range for generation of 'Abstract.Addr's. + -> Gen PParamsAddrsAndUTxO +genPParamsAddrsAndUTxO addrRange = do + abstractPparams <- Abstract.pparamsGen + abstractAddrs <- genAbstractAddrs addrRange + abstractUtxo <- genInitialAbstractUTxO abstractAddrs + pure $ PParamsAddrsAndUTxO abstractPparams abstractAddrs abstractUtxo + +genValidTxWits + :: PParamsAddrsAndUTxO + -> Map Abstract.TxId TxId + -> Gen Abstract.TxWits +genValidTxWits ppau txIdMap = do + abstractTx <- Abstract.genTxFromUTxO + ppauAddrs + (abstractTxFee txIdMap (ppTxFeePolicy pparams) ppauUTxO) + ppauUTxO + pure $ Abstract.makeTxWits ppauUTxO abstractTx + where + PParamsAddrsAndUTxO + { ppauPParams + , ppauAddrs + , ppauUTxO + } = ppau + + pparams = elaboratePParams ppauPParams + +genValidationMode :: Gen TxValidationMode +genValidationMode = Gen.element + [ TxValidation + , TxValidationNoCrypto + , NoTxValidation + ] + +-------------------------------------------------------------------------------- +-- Helpers +-------------------------------------------------------------------------------- + +data PParamsAddrsAndUTxO = PParamsAddrsAndUTxO + { ppauPParams :: !Abstract.PParams + , ppauAddrs :: ![Abstract.Addr] + , ppauUTxO :: !Abstract.UTxO + } deriving (Show) + +-- | Elaborate an 'Abstract.Tx', calculate the 'Concrete.Lovelace' fee, then +-- convert back to an 'Abstract.Lovelace'. +-- n.b. Calculating the fee with 'Abstract.pcMinFee', for example, proved to +-- be ineffective as it utilizes the 'Abstract.Size' of the 'Abstract.Tx' in +-- its calculation when we really need to take into account the actual +-- concrete size in bytes. +abstractTxFee + :: Map Abstract.TxId UTxO.TxId + -> TxFeePolicy + -> Abstract.UTxO + -> Abstract.Tx + -> Abstract.Lovelace +abstractTxFee txIdMap tfp aUtxo aTx = do + let aTxWits = Abstract.makeTxWits aUtxo aTx + ATxAux (Annotated _ txBytes) _ = elaborateTxWitsBS + (elaborateTxId txIdMap) + aTxWits + cLovelace = case tfp of + TxFeePolicyTxSizeLinear txSizeLinear -> + either (panic . show) + (\x -> x) + (calculateTxSizeLinear + txSizeLinear + (fromIntegral $ BS.length txBytes)) + Abstract.Lovelace (lovelaceToInteger cLovelace) + +elaborateTxId :: Map Abstract.TxId UTxO.TxId -> Abstract.TxId -> TxId +elaborateTxId txIdMap abstractTxId = + case M.lookup abstractTxId txIdMap of + Nothing -> panic "elaborateTxId: Missing abstract TxId during elaboration" + Just x -> x + +-------------------------------------------------------------------------------- +-- Main Test Export +-------------------------------------------------------------------------------- + +tests :: TSGroup +tests = $$discoverPropArg diff --git a/cardano-ledger/test/test.hs b/cardano-ledger/test/test.hs index f033b7c1..77fddd99 100644 --- a/cardano-ledger/test/test.hs +++ b/cardano-ledger/test/test.hs @@ -12,6 +12,7 @@ import Test.Options (ShouldAssertNF(..), mainWithTestScenario, tsGroupToTree) import qualified Test.Cardano.Chain.Block.CBOR import qualified Test.Cardano.Chain.Block.Model import qualified Test.Cardano.Chain.Block.Validation +import qualified Test.Cardano.Chain.Block.ValidationMode import qualified Test.Cardano.Chain.Common.Address import qualified Test.Cardano.Chain.Common.CBOR import qualified Test.Cardano.Chain.Common.Compact @@ -30,6 +31,7 @@ import qualified Test.Cardano.Chain.UTxO.CBOR import qualified Test.Cardano.Chain.UTxO.Compact import qualified Test.Cardano.Chain.UTxO.Json import qualified Test.Cardano.Chain.UTxO.Model +import qualified Test.Cardano.Chain.UTxO.ValidationMode import qualified Test.Cardano.Chain.Update.CBOR import qualified Test.Cardano.Chain.Update.Json import qualified Test.Cardano.Chain.Update.Properties @@ -43,6 +45,7 @@ main = <$> [ Test.Cardano.Chain.Block.CBOR.tests , Test.Cardano.Chain.Block.Model.tests , Test.Cardano.Chain.Block.Validation.tests NoAssertNF + , Test.Cardano.Chain.Block.ValidationMode.tests , Test.Cardano.Chain.Common.Address.tests , Test.Cardano.Chain.Common.CBOR.tests , Test.Cardano.Chain.Common.Compact.tests @@ -62,6 +65,7 @@ main = , Test.Cardano.Chain.UTxO.Compact.tests , Test.Cardano.Chain.UTxO.Json.tests , Test.Cardano.Chain.UTxO.Model.tests + , Test.Cardano.Chain.UTxO.ValidationMode.tests , Test.Cardano.Chain.Update.CBOR.tests , Test.Cardano.Chain.Update.Json.tests , Test.Cardano.Chain.Update.Properties.tests diff --git a/crypto/test/Test/Cardano/Crypto/Gen.hs b/crypto/test/Test/Cardano/Crypto/Gen.hs index 0d060d25..bc0ad19e 100644 --- a/crypto/test/Test/Cardano/Crypto/Gen.hs +++ b/crypto/test/Test/Cardano/Crypto/Gen.hs @@ -5,6 +5,7 @@ module Test.Cardano.Crypto.Gen -- * Protocol Magic Generator genProtocolMagic , genProtocolMagicId + , genRequiresNetworkMagic -- * Sign Tag Generator , genSignTag