quickcheck-contractmodel-0.1.4.1
Safe HaskellNone
LanguageHaskell2010

Test.QuickCheck.ContractModel.ThreatModel

Description

The threat modelling framework allows you to write down and test properties of modifications of valid transactions.

A threat model is represented by a value in the ThreatModel monad, and is evaluated in the context of a single valid transaction and the chain state at the point it validated (a ThreatModelEnv). Transactions and chain states can most easily be obtained using a ContractModelResult from runContractModel, but they can in principle come from anywhere.

As an example, here is a ThreatModel that checks that any interaction with myScript requires theToken to be present:

    tokenThreatModel :: ThreatModel ()
    tokenThreatModel = do
      ensureHasInputAt myScript

      let hasToken out = theToken `leqValue` valueOf out
      i <- anyInputSuchThat  hasToken
      o <- anyOutputSuchThat hasToken

      shouldNotValidate $ changeValueOf i (valueOf i <> negateValue theToken)
                       <> changeValueOf o (valueOf o <> negateValue theToken)

For a more complex example see Test.QuickCheck.ContractModel.ThreatModel.DoubleSatisfaction.

Synopsis

Transaction modifiers

Types

data TxModifier Source #

The type of transaction modifiers. When combined using the monoid instance, individual modifications are applied in left-to-right order.

data Input Source #

A transaction input reference togheter with the corresponding TxOut from the UTxO set.

Constructors

Input 

Fields

data Output Source #

A transaction output paired with its index in the transaction.

Constructors

Output 

Fields

type Datum = TxOutDatum CtxTx Era Source #

Type synonym for datums. The CtxTx context means that the actual datum value can be present, not just the hash.

type Redeemer = ScriptData Source #

Redeemers are plain ScriptData.

Modifiers

class IsInputOrOutput t where Source #

Functions common to both Inputs and Outputs.

Methods

changeAddressOf :: t -> AddressAny -> TxModifier Source #

Change the target address of an input or an output. For outputs this means redirecting an output to a different address, and for inputs it means modifying the UTxO set, changing the owner of the given input.

Note: Does not work for script inputs.

changeValueOf :: t -> Value -> TxModifier Source #

Change the value of an input or an output.

changeDatumOf :: t -> Datum -> TxModifier Source #

Change the datum on an input or an output.

addressOf :: t -> AddressAny Source #

Get the address (pubkey or script address) of an input or an output.

valueOf :: t -> Value Source #

Get the value at an input or an output.

addOutput :: AddressAny -> Value -> Datum -> TxModifier Source #

Add a new output of any type (public key or script)

removeOutput :: Output -> TxModifier Source #

Remove an output of any type.

addKeyInput :: AddressAny -> Value -> Datum -> TxModifier Source #

Add a new public key input.

addPlutusScriptInput :: PlutusScript PlutusScriptV2 -> Value -> Datum -> Redeemer -> TxModifier Source #

Add a plutus script input.

addSimpleScriptInput :: SimpleScript SimpleScriptV2 -> Value -> TxModifier Source #

Add a simple script input.

removeInput :: Input -> TxModifier Source #

Remove an input of any type.

changeRedeemerOf :: Input -> Redeemer -> TxModifier Source #

Change the redeemer of a script input.

changeValidityRange :: (TxValidityLowerBound Era, TxValidityUpperBound Era) -> TxModifier Source #

Change the validity range of the transaction.

changeValidityLowerBound :: TxValidityLowerBound Era -> TxModifier Source #

Change the validity lower bound of the transaction.

changeValidityUpperBound :: TxValidityUpperBound Era -> TxModifier Source #

Change the validity upper bound of the transaction.

replaceTx :: Tx Era -> UTxO Era -> TxModifier Source #

The most general transaction modifier. Simply replace the original transaction and UTxO set by the given values. In most cases the modifiers above should be sufficient.

Threat models

data ThreatModel a Source #

The threat model monad is how you construct threat models. It works in the context of a given transaction and the UTxO set at the point where the transaction was validated (see ThreatModelEnv) and lets you construct properties about the validatity of modifications of the original transaction.

data ThreatModelEnv Source #

The context in which a ThreatModel is executed. Contains a transaction, its UTxO set and the protocol parameters. See getThreatModelEnv and originalTx to access this information in a threat model.

Constructors

ThreatModelEnv 

Fields

runThreatModel :: ThreatModel a -> [ThreatModelEnv] -> Property Source #

Evaluate a ThreatModel on a list of transactions with their context. Fails the property if the threat model fails on any of the transactions.

assertThreatModel :: ThreatModel a -> ProtocolParameters -> ContractModelResult state -> Property Source #

Evaluate a ThreatModel on the result of running a ContractModel test (see runContractModel). Checks the threat model on all transactions produced by the test.

Preconditions

threatPrecondition :: ThreatModel a -> ThreatModel a Source #

Check a precondition. If the argument threat model fails, the evaluation of the current transaction is skipped. If all transactions in an evaluation of runThreatModel are skipped it is considered a discarded test for QuickCheck.

Having the argument to threatPrecondition be a threat model computation instead of a plain boolean allows you do express preconditions talking about the validation of modified transactions (using shouldValidate and shouldNotValidate). See ensure for the boolean version.

inPrecondition :: ThreatModel Bool Source #

Returns True if evaluated under a threatPrecondition and False otherwise.

ensure :: Bool -> ThreatModel () Source #

Same as threatPrecondition but takes a boolean and skips the test if the argument is False.

ensureHasInputAt :: AddressAny -> ThreatModel () Source #

Precondition that check that the original transaction has an input at a given address. Useful, for example, to ensure that you only consider transactions that trie to spend a script output from the script under test.

Validation

shouldValidate :: TxModifier -> ThreatModel () Source #

Check that a given modification of the original transaction validates. The modified transaction is printed in counterexample when this fails, or if it succeeds in a precondition and the test fails later.

shouldNotValidate :: TxModifier -> ThreatModel () Source #

Check that a given modification of the original transaction does not validate. The modified transaction is printed in counterexample when it does validate, or if it doesn't in a satisfied precondition and the test fails later.

validate :: TxModifier -> ThreatModel ValidityReport Source #

The most low-level way to validate a modified transaction. In most cases shouldValidate and shouldNotValidate are preferred.

Querying the environment

originalTx :: ThreatModel (Tx Era) Source #

Get the original transaction from the context.

getTxInputs :: ThreatModel [Input] Source #

Get the inputs from the original transaction.

getTxOutputs :: ThreatModel [Output] Source #

Get the outputs from the original transaction.

getRedeemer :: Input -> ThreatModel (Maybe Redeemer) Source #

Get the redeemer (if any) for an input of the original transaction.

Random generation

forAllTM :: Show a => Gen a -> (a -> [a]) -> ThreatModel a Source #

Generate a random value. Takes a QuickCheck generator and a shrink function.

pickAny :: Show a => [a] -> ThreatModel a Source #

Pick a random value from a list. Skips the test if the list is empty.

anySigner :: ThreatModel (Hash PaymentKey) Source #

Pick a random signer of the original transaction.

anyInputSuchThat :: (Input -> Bool) -> ThreatModel Input Source #

Pick a random input satisfying the given predicate.

anyOutputSuchThat :: (Output -> Bool) -> ThreatModel Output Source #

Pick a random output satisfying the given predicate.

Monitoring

counterexampleTM :: String -> ThreatModel () Source #

Print the given string in case this threat model fails. Threat model counterpart of the QuickCheck counterexample function.

tabulateTM :: String -> [String] -> ThreatModel () Source #

Threat model counterpart of QuickCheck's tabulate function.

collectTM :: Show a => a -> ThreatModel () Source #

Threat model counterpart of QuickCheck's collect function.

classifyTM :: Bool -> String -> ThreatModel () Source #

Threat model counterpart of QuickCheck's classify function.

monitorThreatModel :: (Property -> Property) -> ThreatModel () Source #

Monitoring that's shared between all transactions evaulated. Avoid this in favour of tabulateTM, collectTM and classifyTM when possible.

monitorLocalThreatModel :: (Property -> Property) -> ThreatModel () Source #

Monitoring that's local to the current transaction. Use counterexampleTM when possible.

Cardano API helpers

Some convenience functions making it easier to work with Cardano API.

projectAda :: Value -> Value Source #

Keep only the Ada part of a value.

leqValue :: Value -> Value -> Bool Source #

Check if a value is less or equal than another value.

Addresses

keyAddressAny :: Hash PaymentKey -> AddressAny Source #

Construct a public key address.

scriptAddressAny :: ScriptHash -> AddressAny Source #

Construct a script address.

isKeyAddressAny :: AddressAny -> Bool Source #

Check if an address is a public key address.

Datums

txOutDatum :: ScriptData -> TxOutDatum CtxTx Era Source #

Convert ScriptData to a Datum.

toScriptData :: ToData a => a -> ScriptData Source #

Convert a Haskell value to ScriptData for use as a Redeemer or convert to a Datum with txOutDatum.

datumOfTxOut :: TxOut ctx Era -> TxOutDatum ctx Era Source #

Get the datum from a transaction output.

Pretty printing

The framework already prints the original transaction and the results of validating modified transactions in counterexamples. To include more information you can use counterexampleTM with the functions below.

paragraph :: [String] -> String Source #

Format a list of strings as a paragraph. The structure of the list is not considered other than inserting whitespace between consecutive elements. Use with counterexampleTM when printing longer texts.

prettyAddress :: AddressAny -> Doc Source #

prettyValue :: Value -> Doc Source #