Skip to content

Commit

Permalink
Merge pull request #87 from mlabs-haskell/uhbif19/cem-types-deriving-…
Browse files Browse the repository at this point in the history
…utils

Add deriving utils and separate `CEMScriptTypes`
  • Loading branch information
uhbif19 authored Jun 11, 2024
2 parents d63eb2c + 56d95d3 commit c5b426a
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 67 deletions.
1 change: 1 addition & 0 deletions cem-script.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ library
Cardano.CEM.OnChain
Cardano.CEM.Stages
Cardano.CEM.Testing.StateMachine
Cardano.CEM.TH

other-modules: Cardano.CEM.Monads.L1Commons
build-depends:
Expand Down
40 changes: 22 additions & 18 deletions src/Cardano/CEM.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import Data.Map qualified as Map
-- Plutus imports
import PlutusLedgerApi.V1.Address (Address, pubKeyHashAddress)
import PlutusLedgerApi.V1.Crypto (PubKeyHash)
import PlutusLedgerApi.V2 (
ToData (..),
Value,
)
import PlutusLedgerApi.V2 (ToData (..), Value)
import PlutusTx.Show.TH (deriveShow)

-- Project imports
Expand Down Expand Up @@ -81,20 +78,12 @@ type DefaultConstraints datatype =
, Prelude.Show datatype
)

class
( HasSpine (Transition script)
, HasSpine (State script)
, Stages (Stage script)
, DefaultConstraints (Stage script)
, DefaultConstraints (Transition script)
, DefaultConstraints (State script)
, DefaultConstraints (Params script)
, DefaultConstraints (StageParams (Stage script))
) =>
CEMScript script
where
-- | `Params` is immutable part of script Datum,
-- | it should be used to encode all
{- | All associated types for `CEMScript`
They are separated to simplify TH deriving
-}
class CEMScriptTypes script where
-- \| `Params` is immutable part of script Datum,
-- \| it should be used to encode all
type Params script = params | params -> script

-- | `Stage` is datatype encoding all `Interval`s specified by script.
Expand All @@ -103,13 +92,28 @@ class
-- | which is stored immutable in script Datum as well.
type Stage script

type Stage script = SingleStage

-- | `State` is changing part of script Datum.
-- | It is in
type State script = params | params -> script

-- | Transitions for deterministic CEM-machine
type Transition script = transition | transition -> script

class
( HasSpine (Transition script)
, HasSpine (State script)
, Stages (Stage script)
, DefaultConstraints (Stage script)
, DefaultConstraints (Transition script)
, DefaultConstraints (State script)
, DefaultConstraints (Params script)
, DefaultConstraints (StageParams (Stage script))
, CEMScriptTypes script
) =>
CEMScript script
where
-- | Each kind of Transition has statically associated Stage
-- from/to `State`s spines
transitionStage ::
Expand Down
22 changes: 7 additions & 15 deletions src/Cardano/CEM/Examples/Auction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ import PlutusLedgerApi.V1.Time (POSIXTime)
import PlutusLedgerApi.V1.Value (CurrencySymbol (..), TokenName (..), singleton)
import PlutusLedgerApi.V2 (Value)
import PlutusTx qualified
import PlutusTx.Show.TH (deriveShow)

import Cardano.CEM
import Cardano.CEM.Stages
import Data.Spine
import Cardano.CEM.Stages (Stages (..))
import Cardano.CEM.TH (deriveCEMAssociatedTypes, deriveStageAssociatedTypes)

-- Simple no-deposit auction

Expand Down Expand Up @@ -66,24 +65,17 @@ data SimpleAuctionTransition
deriving stock (Prelude.Eq, Prelude.Show)

PlutusTx.unstableMakeIsData ''Bid
PlutusTx.unstableMakeIsData 'MkAuctionParams
PlutusTx.unstableMakeIsData 'NotStarted
PlutusTx.unstableMakeIsData 'MakeBid
PlutusTx.unstableMakeIsData ''SimpleAuctionStage
PlutusTx.unstableMakeIsData ''SimpleAuctionStageParams
deriveShow ''SimpleAuction

deriveSpine ''SimpleAuctionTransition
deriveSpine ''SimpleAuctionState

instance CEMScript SimpleAuction where
instance CEMScriptTypes SimpleAuction where
type Stage SimpleAuction = SimpleAuctionStage
type Params SimpleAuction = SimpleAuctionParams

type State SimpleAuction = SimpleAuctionState

type Transition SimpleAuction = SimpleAuctionTransition

$(deriveStageAssociatedTypes ''SimpleAuctionStage)
$(deriveCEMAssociatedTypes False ''SimpleAuction)

instance CEMScript SimpleAuction where
transitionStage Proxy =
Map.fromList
[ (CreateSpine, (Open, Nothing, Just NotStartedSpine))
Expand Down
20 changes: 3 additions & 17 deletions src/Cardano/CEM/Examples/Compilation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,11 @@

module Cardano.CEM.Examples.Compilation where

import PlutusTx qualified

import Data.Proxy (Proxy (..))

import PlutusLedgerApi.V2 (serialiseCompiledCode)

import Cardano.CEM.Examples.Auction
import Cardano.CEM.Examples.Voting
import Cardano.CEM.OnChain (CEMScriptCompiled (..), genericCEMScript)
import Cardano.CEM.Stages (SingleStage)

instance CEMScriptCompiled SimpleAuction where
{-# INLINEABLE cemScriptCompiled #-}
cemScriptCompiled Proxy =
serialiseCompiledCode
$(PlutusTx.compileUntyped (genericCEMScript ''SimpleAuction ''SimpleAuctionStage))
import Cardano.CEM.TH

instance CEMScriptCompiled SimpleVoting where
{-# INLINEABLE cemScriptCompiled #-}
cemScriptCompiled Proxy =
serialiseCompiledCode
$(PlutusTx.compileUntyped (genericCEMScript ''SimpleVoting ''SingleStage))
$(compileCEM ''SimpleAuction)
$(compileCEM ''SimpleVoting)
17 changes: 5 additions & 12 deletions src/Cardano/CEM/Examples/Voting.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import PlutusLedgerApi.V1.Crypto (PubKeyHash)
import PlutusLedgerApi.V2 (Value)
import PlutusTx qualified
import PlutusTx.AssocMap qualified as PMap
import PlutusTx.Show.TH (deriveShow)

import Cardano.CEM
import Cardano.CEM.Stages
import Data.Spine (deriveSpine)
import Cardano.CEM.TH (deriveCEMAssociatedTypes)

-- Voting

Expand Down Expand Up @@ -88,21 +87,15 @@ data SimpleVotingTransition

PlutusTx.unstableMakeIsData ''VoteValue
PlutusTx.unstableMakeIsData ''JuryPolicy
PlutusTx.unstableMakeIsData ''SimpleVotingState
PlutusTx.unstableMakeIsData ''SimpleVotingParams
PlutusTx.unstableMakeIsData ''SimpleVotingTransition

deriveShow ''SimpleVoting

deriveSpine ''SimpleVotingTransition
deriveSpine ''SimpleVotingState

instance CEMScript SimpleVoting where
type Stage SimpleVoting = SingleStage
instance CEMScriptTypes SimpleVoting where
type Params SimpleVoting = SimpleVotingParams
type State SimpleVoting = SimpleVotingState
type Transition SimpleVoting = SimpleVotingTransition

$(deriveCEMAssociatedTypes False ''SimpleVoting)

instance CEMScript SimpleVoting where
transitionStage _ =
Map.fromList
[ (CreateSpine, (Always, Nothing, Just NotStartedSpine))
Expand Down
1 change: 0 additions & 1 deletion src/Cardano/CEM/Monads/L1.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module Cardano.CEM.Monads.L1 where
import Prelude

import Control.Monad.Reader (MonadReader (..), ReaderT (..))
import Control.Monad.Trans (MonadIO (..))
import Data.ByteString qualified as BS
import Data.Set qualified as Set

Expand Down
1 change: 0 additions & 1 deletion src/Cardano/CEM/Monads/L1Commons.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ module Cardano.CEM.Monads.L1Commons where

import Prelude

import Control.Monad.Except (ExceptT (..), runExceptT)
import Data.List (nub)
import Data.Map qualified as Map

Expand Down
2 changes: 0 additions & 2 deletions src/Cardano/CEM/OffChain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import Prelude

-- Haskell imports
import Control.Concurrent (threadDelay)
import Control.Monad.Except (ExceptT (..), MonadError (..), runExceptT)
import Control.Monad.Trans (MonadIO (..), MonadTrans (..))
import Data.Bifunctor (Bifunctor (..))
import Data.Data (Proxy (..))
import Data.List (find)
Expand Down
98 changes: 98 additions & 0 deletions src/Cardano/CEM/TH.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
module Cardano.CEM.TH (
deriveCEMAssociatedTypes,
compileCEM,
unstableMakeIsDataSchema,
deriveStageAssociatedTypes,
defaultIndex,
unstableMakeHasSchemaInstance,
) where

import Prelude

import Data.Data (Proxy (..))
import GHC.Num.Natural (Natural)
import Language.Haskell.TH
import Language.Haskell.TH.Syntax (sequenceQ)

import PlutusTx qualified
import PlutusTx.Blueprint.TH

import Language.Haskell.TH.Datatype (
ConstructorInfo (..),
DatatypeInfo (..),
reifyDatatype,
)

import Cardano.CEM (CEMScriptTypes (..))
import Cardano.CEM.OnChain (CEMScriptCompiled (..), genericCEMScript)
import Cardano.CEM.Stages (Stages (..))
import Data.Spine (deriveSpine)
import PlutusTx.Show (deriveShow)

defaultIndex :: Name -> Q [(Name, Natural)]
defaultIndex name = do
info <- reifyDatatype name
pure $ zip (constructorName <$> datatypeCons info) [0 ..]

unstableMakeIsDataSchema :: Name -> Q [InstanceDec]
unstableMakeIsDataSchema name = do
index <- defaultIndex name
PlutusTx.makeIsDataSchemaIndexed name index

unstableMakeHasSchemaInstance :: Name -> Q [InstanceDec]
unstableMakeHasSchemaInstance name = do
index <- defaultIndex name
dec <- makeHasSchemaInstance name index
return [dec]

-- | Get `TypeFamily Datatype` result as TH Name
resolveFamily :: Name -> Name -> Q Name
resolveFamily familyName argName = do
argType <- conT argName
[TySynInstD (TySynEqn _ _ (ConT name))] <-
reifyInstances familyName [argType]
return name

deriveStageAssociatedTypes :: Name -> Q [Dec]
deriveStageAssociatedTypes stageName = do
stageParamsName <- resolveFamily ''StageParams stageName
declss <-
sequenceQ
[ PlutusTx.unstableMakeIsData stageName
, PlutusTx.unstableMakeIsData stageParamsName
]
return $ concat declss

deriveCEMAssociatedTypes :: Bool -> Name -> Q [Dec]
deriveCEMAssociatedTypes deriveBlueprint scriptName = do
declss <-
sequenceQ
[ -- Data
deriveFamily isDataDeriver ''Params
, deriveFamily isDataDeriver ''State
, deriveFamily isDataDeriver ''Transition
, -- Spines
deriveFamily deriveSpine ''State
, deriveFamily deriveSpine ''Transition
, -- Other
deriveShow scriptName
]
return $ concat declss
where
isDataDeriver =
if deriveBlueprint
then unstableMakeIsDataSchema
else PlutusTx.unstableMakeIsData
deriveFamily deriver family = do
name <- resolveFamily family scriptName
deriver name

compileCEM :: Name -> Q [Dec]
compileCEM name = do
stageName <- resolveFamily ''Stage name
let compiled = PlutusTx.compileUntyped $ genericCEMScript name stageName
[d|
instance CEMScriptCompiled $(conT name) where
{-# INLINEABLE cemScriptCompiled #-}
cemScriptCompiled Proxy = serialiseCompiledCode $(compiled)
|]
1 change: 0 additions & 1 deletion test/Utils.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module Utils where

import Prelude

import Control.Monad.Trans (MonadIO (..))
import Data.Map (keys)

import PlutusLedgerApi.V1.Interval (always)
Expand Down

0 comments on commit c5b426a

Please sign in to comment.