Skip to content

Commit

Permalink
HasBlueprintSchema and HasBlueprintDefinition instances
Browse files Browse the repository at this point in the history
  • Loading branch information
Unisay committed Jul 4, 2024
1 parent d031015 commit 7046453
Show file tree
Hide file tree
Showing 32 changed files with 1,152 additions and 512 deletions.
6 changes: 3 additions & 3 deletions doc/docusaurus/docs/using-plutus-tx/producing-a-blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ Since every type in the `referencedTypes` list is going to have its derived JSON

<LiteralInclude file="Example/Cip57/Blueprint/Main.hs" language="haskell" title="generic instances" start="-- BEGIN generic instances" end="-- END generic instances" />

- An instance of the `AsDefinitionId` type class. Most of the time it could be derived generically with the `anyclass` strategy; for example:
- An instance of the `HasBlueprintDefinition` type class. Most of the time it could be derived generically with the `anyclass` strategy; for example:

<LiteralInclude file="Example/Cip57/Blueprint/Main.hs" language="haskell" title="AsDefinitionId instances" start="-- BEGIN AsDefinitionId instances" end="-- END AsDefinitionId instances" />
<LiteralInclude file="Example/Cip57/Blueprint/Main.hs" language="haskell" title="HasBlueprintDefinition instances" start="-- BEGIN HasBlueprintDefinition instances" end="-- END HasBlueprintDefinition instances" />

- An instance of the `HasSchema` type class. If your validator exposes standard supported types like `Integer` or `Bool`, you don't need to define this instance. If your validator uses custom types, then you should be deriving it using the `makeIsDataSchemaIndexed` Template Haskell function, which derives it alongside with the corresponding [ToBuiltinData]/[FromBuiltinData] instances; for example:
- An instance of the `HasBlueprintSchema` type class. If your validator exposes standard supported types like `Integer` or `Bool`, you don't need to define this instance. If your validator uses custom types, then you should be deriving it using the `makeIsDataSchemaIndexed` Template Haskell function, which derives it alongside with the corresponding [ToBuiltinData]/[FromBuiltinData] instances; for example:

<LiteralInclude file="Example/Cip57/Blueprint/Main.hs" language="haskell" title="makeIsDataSchemaIndexed" start="-- BEGIN makeIsDataSchemaIndexed" end="-- END makeIsDataSchemaIndexed" />

Expand Down
99 changes: 95 additions & 4 deletions doc/docusaurus/plutus.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,40 @@
],
"definitions": {
"Bool": {
"dataType": "#boolean"
"oneOf": [
{
"dataType": "constructor",
"fields": [],
"index": 0
},
{
"dataType": "constructor",
"fields": [],
"index": 1
}
]
},
"CurrencySymbol": {
"title": "CurrencySymbol",
"dataType": "bytes"
},
"DiffMilliSeconds": {
"title": "DiffMilliSeconds",
"dataType": "constructor",
"fields": [
{
"$ref": "#/definitions/Integer"
}
],
"index": 0
},
"Integer": {
"dataType": "integer"
},
"Lovelace": {
"title": "Lovelace",
"dataType": "integer"
},
"MyParams": {
"title": "Title for the MyParams definition",
"description": "Description for the MyParams definition",
Expand All @@ -68,25 +97,87 @@
},
{
"$ref": "#/definitions/Integer"
},
{
"$ref": "#/definitions/PubKeyHash"
},
{
"$ref": "#/definitions/DiffMilliSeconds"
},
{
"$ref": "#/definitions/POSIXTime"
}
],
"index": 0
},
"MyRedeemer": {
"oneOf": [
{
"$comment": "Left redeemer",
"dataType": "constructor",
"fields": [],
"index": 0
},
{
"$comment": "Right redeemer",
"$comment": "Left redeemer",
"dataType": "constructor",
"fields": [],
"fields": [
{
"$ref": "#/definitions/Lovelace"
}
],
"index": 1
},
{
"$comment": "Right redeemer",
"dataType": "constructor",
"fields": [
{
"$ref": "#/definitions/Value"
}
],
"index": 2
}
]
},
"POSIXTime": {
"title": "POSIXTime",
"dataType": "constructor",
"fields": [
{
"$ref": "#/definitions/Integer"
}
],
"index": 0
},
"PubKeyHash": {
"title": "PubKeyHash",
"dataType": "bytes"
},
"TokenName": {
"title": "TokenName",
"dataType": "bytes"
},
"Value": {
"title": "Value",
"dataType": "constructor",
"fields": [
{
"dataType": "map",
"keys": {
"$ref": "#/definitions/CurrencySymbol"
},
"values": {
"dataType": "map",
"keys": {
"$ref": "#/definitions/TokenName"
},
"values": {
"$ref": "#/definitions/Integer"
}
}
}
],
"index": 0
}
}
}
36 changes: 21 additions & 15 deletions doc/docusaurus/static/code/Example/Cip57/Blueprint/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImportQualifiedPost #-}
Expand All @@ -19,16 +20,15 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}

{-# OPTIONS_GHC -Wno-missing-signatures #-}
{-# OPTIONS_GHC -fno-full-laziness #-}
{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
{-# OPTIONS_GHC -fno-full-laziness #-}
{-# OPTIONS_GHC -fno-spec-constr #-}
{-# OPTIONS_GHC -fno-specialise #-}
{-# OPTIONS_GHC -fno-strictness #-}
{-# OPTIONS_GHC -fno-unbox-strict-fields #-}
{-# OPTIONS_GHC -fno-unbox-small-strict-fields #-}
{-# OPTIONS_GHC -fno-unbox-strict-fields #-}
{-# OPTIONS_GHC -fplugin-opt PlutusTx.Plugin:target-version=1.0.0 #-}

-- END pragmas
Expand All @@ -44,8 +44,10 @@ import PlutusTx.Prelude
import Data.Set qualified as Set
import GHC.Generics (Generic)
import Paths_docusaurus_examples (getDataFileName)
import PlutusLedgerApi.V3 (Datum (..), Redeemer (..), ScriptContext (..),
ScriptInfo (SpendingScript), UnsafeFromData (..))
import PlutusLedgerApi.V1.Crypto (PubKeyHash)
import PlutusLedgerApi.V1.Time (DiffMilliSeconds, POSIXTime)
import PlutusLedgerApi.V3 (Datum (..), Lovelace, Redeemer (..), ScriptContext (..),
ScriptInfo (SpendingScript), UnsafeFromData (..), Value)
import PlutusTx.Blueprint.TH (makeIsDataSchemaIndexed)
import Prelude (FilePath, IO)

Expand All @@ -69,19 +71,22 @@ import Prelude (FilePath, IO)

type MyDatum = Integer

data MyRedeemer = R1 | R2
data MyRedeemer = R0 | R1 Lovelace | R2 Value

data MyParams = MkMyParams
{ myBool :: Bool
, myInteger :: Integer
{ myBool :: Bool
, myInteger :: Integer
, myPubKey :: PubKeyHash
, myDiffMillis :: DiffMilliSeconds
, myPOSIXTime :: POSIXTime
}

-- END interface types
-- BLOCK6
-- BEGIN makeIsDataSchemaIndexed MyParams

$(makeIsDataSchemaIndexed ''MyParams [('MkMyParams, 0)])
$(makeIsDataSchemaIndexed ''MyRedeemer [('R1, 0), ('R2, 1)])
$(makeIsDataSchemaIndexed ''MyRedeemer [('R0, 0), ('R1, 1), ('R2, 2)])

-- END makeIsDataSchemaIndexed MyParams
-- BLOCK7
Expand All @@ -92,20 +97,21 @@ deriving stock instance Generic MyRedeemer

-- END generic instances
-- BLOCK8
-- BEGIN AsDefinitionId instances
-- BEGIN HasBlueprintDefinition instances

deriving anyclass instance AsDefinitionId MyParams
deriving anyclass instance AsDefinitionId MyRedeemer
deriving anyclass instance HasBlueprintDefinition MyParams
deriving anyclass instance HasBlueprintDefinition MyRedeemer

-- END AsDefinitionId instances
-- END HasBlueprintDefinition instances
-- BLOCK9
-- BEGIN validator

typedValidator :: MyParams -> MyDatum -> MyRedeemer -> Bool
typedValidator MkMyParams{..} datum redeemer =
case redeemer of
R1 -> myBool
R2 -> myInteger == datum
R0 -> myBool
R1{} -> myBool
R2{} -> myInteger == datum

untypedValidator :: MyParams -> BuiltinData -> BuiltinUnit
untypedValidator params scriptContext =
Expand Down
90 changes: 49 additions & 41 deletions plutus-ledger-api/src/PlutusLedgerApi/V1/Address.hs
Original file line number Diff line number Diff line change
@@ -1,78 +1,86 @@
-- editorconfig-checker-disable-file
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ViewPatterns #-}

{-# OPTIONS_GHC -fno-specialise #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
{-# OPTIONS_GHC -fno-specialise #-}

module PlutusLedgerApi.V1.Address
( Address (..)
, pubKeyHashAddress
, scriptHashAddress
, toPubKeyHash
, toScriptHash
, stakingCredential
) where
module PlutusLedgerApi.V1.Address where

import Control.DeepSeq (NFData)
import Data.Typeable (Typeable)
import GHC.Generics (Generic)
import PlutusLedgerApi.V1.Credential (Credential (..), StakingCredential)
import PlutusLedgerApi.V1.Crypto (PubKeyHash)
import PlutusLedgerApi.V1.Scripts (ScriptHash)
import PlutusTx qualified
import PlutusTx.Blueprint.Definition (HasBlueprintDefinition, definitionRef)
import PlutusTx.Bool qualified as PlutusTx
import PlutusTx.Eq qualified as PlutusTx
import Prettyprinter

import PlutusLedgerApi.V1.Credential (Credential (..), StakingCredential)
import PlutusLedgerApi.V1.Crypto
import PlutusLedgerApi.V1.Scripts
import Prettyprinter (Pretty (pretty), parens, (<+>))

-- | An address may contain two credentials, the payment credential and optionally a 'StakingCredential'.
-- | An address may contain two credentials,
-- the payment credential and optionally a 'StakingCredential'.
data Address = Address
{ addressCredential :: Credential -- ^ the payment credential
, addressStakingCredential :: Maybe StakingCredential -- ^ the staking credential
}
deriving stock (Eq, Ord, Show, Generic)
deriving anyclass (NFData)
{ addressCredential :: Credential
-- ^ the payment credential
, addressStakingCredential :: Maybe StakingCredential
-- ^ the staking credential
}
deriving stock (Eq, Ord, Show, Generic, Typeable)
deriving anyclass (NFData, HasBlueprintDefinition)

instance Pretty Address where
pretty (Address cred stakingCred) =
let staking = maybe "no staking credential" pretty stakingCred in
pretty cred <+> parens staking
pretty (Address cred stakingCred) =
let staking = maybe "no staking credential" pretty stakingCred
in pretty cred <+> parens staking

instance PlutusTx.Eq Address where
{-# INLINABLE (==) #-}
Address cred stakingCred == Address cred' stakingCred' =
cred PlutusTx.== cred'
PlutusTx.&& stakingCred PlutusTx.== stakingCred'
{-# INLINEABLE (==) #-}
Address cred stakingCred == Address cred' stakingCred' =
cred
PlutusTx.== cred'
PlutusTx.&& stakingCred
PlutusTx.== stakingCred'

{-# INLINABLE pubKeyHashAddress #-}
-- | The address that should be targeted by a transaction output locked by the public key with the given hash.
{-# INLINEABLE pubKeyHashAddress #-}

-- | The address that should be targeted by a transaction output
-- locked by the public key with the given hash.
pubKeyHashAddress :: PubKeyHash -> Address
pubKeyHashAddress pkh = Address (PubKeyCredential pkh) Nothing

{-# INLINABLE toPubKeyHash #-}
{-# INLINEABLE toPubKeyHash #-}

-- | The PubKeyHash of the address, if any
toPubKeyHash :: Address -> Maybe PubKeyHash
toPubKeyHash (Address (PubKeyCredential k) _) = Just k
toPubKeyHash _ = Nothing

{-# INLINABLE toScriptHash #-}
{-# INLINEABLE toScriptHash #-}

-- | The validator hash of the address, if any
toScriptHash :: Address -> Maybe ScriptHash
toScriptHash (Address (ScriptCredential k) _) = Just k
toScriptHash _ = Nothing

{-# INLINABLE scriptHashAddress #-}
-- | The address that should be used by a transaction output locked by the given validator script hash.
{-# INLINEABLE scriptHashAddress #-}

-- | The address that should be used by a transaction output
-- locked by the given validator script hash.
scriptHashAddress :: ScriptHash -> Address
scriptHashAddress vh = Address (ScriptCredential vh) Nothing

{-# INLINABLE stakingCredential #-}
{-# INLINEABLE stakingCredential #-}

-- | The staking credential of an address (if any)
stakingCredential :: Address -> Maybe StakingCredential
stakingCredential (Address _ s) = s

PlutusTx.makeIsDataIndexed ''Address [('Address,0)]
PlutusTx.makeIsDataSchemaIndexed ''Address [('Address, 0)]
PlutusTx.makeLift ''Address
8 changes: 5 additions & 3 deletions plutus-ledger-api/src/PlutusLedgerApi/V1/Bytes.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import Data.Either.Extras (unsafeFromEither)
import Data.String (IsString (..))
import Data.Text qualified as Text
import Data.Text.Encoding qualified as TE
import Data.Typeable (Typeable)
import Data.Word (Word8)
import GHC.Generics (Generic)
import PlutusTx
import PlutusTx hiding (Typeable)
import PlutusTx.Blueprint.Definition (HasBlueprintDefinition)
import PlutusTx.Prelude qualified as P
import Prettyprinter.Extras (Pretty, PrettyShow (..))

Expand Down Expand Up @@ -68,9 +70,9 @@ fromHex = fmap (LedgerBytes . P.toBuiltin) . asBSLiteral
withBytes f = fmap BS.pack . f . BS.unpack

newtype LedgerBytes = LedgerBytes { getLedgerBytes :: P.BuiltinByteString }
deriving stock (Eq, Ord, Generic)
deriving stock (Eq, Ord, Generic, Typeable)
deriving newtype (P.Eq, P.Ord, PlutusTx.ToData, PlutusTx.FromData, PlutusTx.UnsafeFromData)
deriving anyclass (NFData)
deriving anyclass (NFData, HasBlueprintDefinition)
deriving Pretty via (PrettyShow LedgerBytes)

-- | Lift a Haskell bytestring to the Plutus abstraction 'LedgerBytes'
Expand Down
Loading

0 comments on commit 7046453

Please sign in to comment.