Cabal setup

Let us organise our code for this course project. We will be writing a number of Plutus validators and our project can have the same structure as plutus-scripts.

The .cabal file

We start off by creating a new directory and initialising a cabal project.

mkdir hpm-validators && cd hpm-validators
cabal init

This will create a default cabal project structure for us that looks like this:

├── app
   └── Main.hs
├── CHANGELOG.md
└── hpm-validators.cabal

We will place all our source code in the src/ directory so let's rename the app directory to src. Inspecting the hpm-validators.cabal file shows that the project was initialised as an executable, but we will be building a library of validators so we can change that to a library and specify the hs-source-dirs to src. The rest of the file we can simply copy from the plutus-scripts.cabal template (most notably the build-depends section). Our complete hpm-validators.cabal file looks like this:

cabal-version:      2.4
name:               hpm-validators
version:            0.1.0.0

-- A short (one-line) description of the package.
-- synopsis:

-- A longer description of the package.
-- description:

-- A URL where users can report bugs.
-- bug-reports:

-- The license under which the package is released.
-- license:

-- The package author(s).
-- author:

-- An email address to which users can send suggestions, bug reports, and patches.
-- maintainer:

-- A copyright notice.
-- copyright:
-- category:
extra-source-files: CHANGELOG.md

library
    hs-source-dirs:      src
    exposed-modules:     SimplestSuccess

    build-depends:       aeson
                        , base ^>=4.14.1.0
                        , bytestring
                        , containers
                        , cardano-api
                        , data-default
                        , freer-extras
                        , plutus-contract
                        , plutus-ledger
                        , plutus-ledger-api
                        , plutus-ledger-constraints
                        , plutus-script-utils
                        , plutus-tx-plugin
                        , plutus-tx
                        , text
                        , serialise
  default-language:    Haskell2010
  ghc-options:         -Wall -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas -fno-strictness -fno-spec-constr -fno-specialise

Our exposed-modules: exposes SimplestSuccess as that will be the first validator script we write.

Note that there is also an interactive option cabal init -i that you can try out.

The cabal.project file

We do not need to think too much about the cabal.project file. Simply copy the full file from plutus-scripts/cabal.project as it contains all the dependencies we need. For reference, the full file looks like this:

-- Custom repository for cardano haskell packages
-- See https://github.com/IntersectMBO/cardano-haskell-packages on how to use CHaP in a Haskell project.
repository cardano-haskell-packages
  url: https://chap.intersectmbo.org
  secure: True
  root-keys:
    3e0cce471cf09815f930210f7827266fd09045445d65923e6d0238a6cd15126f
    443abb7fb497a134c343faf52f0b659bd7999bc06b7f63fa76dc99d631f9bea1
    a86a1f6ce86c449c46666bda44268677abf29b5b2d2eb5ec7af903ec2f117a82
    bcec67e8e99cabfa7764d75ad9b158d72bfacf70ca1d0ec8bc6b4406d1bf8413
    c00aae8461a256275598500ea0e187588c35a5d5d7454fb57eac18d9edb86a56
    d4a35cd3121aa00d18544bb0ac01c3e1691d618f462c46129271bccf39f7e8ee

packages: hpm-validators.cabal

index-state: 2022-11-14T00:20:02Z

index-state:
  , hackage.haskell.org 2022-11-14T00:20:02Z
  , cardano-haskell-packages 2022-11-17T04:56:26Z

-- We never, ever, want this.
write-ghc-environment-files: never

allow-newer:
  -- cardano-ledger packages need aeson >2, the following packages have a
  -- too restictive upper bounds on aeson, so we relax them here. The hackage
  -- trustees can make a revision to these packages cabal file to solve the
  -- issue permanently.
  , ekg:aeson
  , ekg-json:aeson
  , openapi3:aeson
  , servant:aeson
  , servant-client-core:aeson
  , servant-server:aeson

constraints:
  -- cardano-prelude-0.1.0.0 needs
  , protolude <0.3.1

  -- cardano-ledger-byron-0.1.0.0 needs
  , cardano-binary <1.5.0.1

  -- plutus-core-1.0.0.1 needs
  , cardano-crypto-class >2.0.0.0
  , algebraic-graphs <0.7

  -- cardano-ledger-core-0.1.0.0 needs
  , cardano-crypto-class <2.0.0.1

  -- cardano-crypto-class-2.0.0.0.1 needs
  , cardano-prelude <0.1.0.1

  -- dbvar from cardano-wallet needs
  , io-classes <0.3.0.0

  -- newer typed-protocols need io-classes>=0.3.0.0 which is incompatible with dbvar's constraint above
  , typed-protocols==0.1.0.0

-- DELETE
-- The plugin will typically fail when producing Haddock documentation. However,
-- in this instance you can simply tell it to defer any errors to runtime (which
-- will never happen since you're building documentation).
--
-- So, any package using 'PlutusTx.compile' in the code for which you need to
-- generate haddock documentation should use the following 'haddock-options'.
--package plutus-ledger
--  haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors"
--package plutus-script-utils
--  haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors"
--package plutus-contract
--  haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors"

-- These packages appear in our dependency tree and are very slow to build.
-- Empirically, turning off optimization shaves off ~50% build time.
-- It also mildly improves recompilation avoidance.
-- For dev work we don't care about performance so much, so this is okay.
-- package cardano-ledger-alonzo
--   optimization: False
-- package ouroboros-consensus-shelley
--   optimization: False
-- package ouroboros-consensus-cardano
--   optimization: False
-- package cardano-api
--   optimization: False
-- package cardano-wallet
--   optimization: False
-- package cardano-wallet-core
--   optimization: False
-- package cardano-wallet-cli
--   optimization: False
-- package cardano-wallet-launcher
--   optimization: False
-- package cardano-wallet-core-integration
--   optimization: False

-- Waiting for plutus-apps CHaP to be published
source-repository-package
  type: git
  location: https://github.com/intersectMBO/plutus-apps.git
  tag: 65ddfa5d467ed64f8709d7db9faf96151942da82
  subdir:
    cardano-streaming
    doc
    freer-extras
    marconi
    marconi-mamba
    playground-common
    pab-blockfrost
    plutus-chain-index
    plutus-chain-index-core
    plutus-contract
    plutus-contract-certification
    plutus-example
    plutus-ledger
    plutus-ledger-constraints
    plutus-pab
    plutus-pab-executables
    plutus-script-utils
    plutus-tx-constraints
    plutus-use-cases
    rewindable-index

-- Direct dependency.
source-repository-package
    type: git
    location: https://github.com/intersectMBO/quickcheck-dynamic
    tag: c272906361471d684440f76c297e29ab760f6a1e

-- Should follow cardano-wallet.
source-repository-package
    type: git
    location: https://github.com/intersectMBO/cardano-addresses
    tag: b7273a5d3c21f1a003595ebf1e1f79c28cd72513
    subdir:
      -- cardano-addresses-cli
      command-line
      -- cardano-addresses
      core

-- Direct dependency.
-- Compared to others, cardano-wallet doesn't bump dependencies very often.
-- Making it a good place to start when bumping dependencies.
-- As, for example, bumping the node first highly risks breaking API with the wallet.
-- Unless early bug fixes are required, this is fine as the wallet tracks stable releases of the node.
-- And it is indeed nice for plutus-apps to track stable releases of the node too.
--
-- The current version is dated 2022/08/10
source-repository-package
    type: git
    location: https://github.com/intersectMBO/cardano-wallet
    tag: 18a931648550246695c790578d4a55ee2f10463e
    subdir:
      lib/cli
      lib/core
      lib/core-integration
      lib/dbvar
      lib/launcher
      lib/numeric
      lib/shelley
      lib/strict-non-empty-containers
      lib/test-utils
      lib/text-class

-- This is needed because we rely on an unreleased feature
-- https://github.com/intersectMBO/cardano-ledger/pull/3111
source-repository-package
    type: git
    location: https://github.com/intersectMBO/cardano-ledger
    tag: da3e9ae10cf9ef0b805a046c84745f06643583c2
    subdir:
      eras/alonzo/impl
      eras/alonzo/test-suite
      eras/babbage/impl
      eras/babbage/test-suite
      eras/byron/chain/executable-spec
      eras/byron/crypto
      eras/byron/crypto/test
      eras/byron/ledger/executable-spec
      eras/byron/ledger/impl
      eras/byron/ledger/impl/test
      eras/shelley/impl
      eras/shelley/test-suite
      eras/shelley-ma/impl
      eras/shelley-ma/test-suite
      libs/cardano-ledger-core
      libs/cardano-ledger-pretty
      libs/cardano-protocol-tpraos
      libs/cardano-data
      libs/vector-map
      libs/set-algebra
      libs/small-steps
      libs/small-steps-test
      libs/non-integral

The project structure that we will create in this course looks like this:

hpm-validators
├── cabal.project 
├── CHANGELOG.md
├── compiled                        # Compiled assets and validators 
├── dist-newstyle
├── hpm-validators.cabal
├── src/                            # Haskell source code
   ├── DeadlineParam.hs
   ├── ExploringScriptContext.hs
   ├── GuessingGame.hs
   ├── Helpers/
   ├── MintingPolicy.hs
   ├── SharedWallet.hs
   ├── SharedWalletParam.hs
   ├── SimplestSuccess.hs
   └── StakingValidator.hs
└── testnet/                        # Scripts and files for testing validators
    ├── address/
    ├── build-addresses.sh
    ├── DeadlineParam/
    ├── ExploringScriptContext/
    ├── GuessingGame/
    ├── MintingPolicy/
    ├── SharedWallet/
    ├── SharedWalletParam/
    ├── SimplestSuccess/
    └── StakingValidator/

Last updated