IntersectMBO / plutus

The Plutus language implementation and tools
Apache License 2.0
1.56k stars 479 forks source link

Types declared with 'newtype" as list in Datum or Redeemer make plutus compiler fail when type declaration is in a separate file #4045

Closed Sbcdn closed 2 years ago

Sbcdn commented 2 years ago

Area

[x] Plutus Foundation Related to the GHC plugin, Haskell-to-Plutus compiler, on-chain code [] Plutus Application Framework Related to the Plutus application backend (PAB), emulator, Plutus libraries [] Marlowe Related to Marlowe [] Other Any other topic (Playgrounds, etc.)

Summary

When separating code over different files e.g. Types.hs and OnChain.hs and using a list of a "newtype" declaration in Datum or Redeemer, the plutus compiler fails. If the declaration of the "newtype" and Datum/Redeemer is in the same file as the
"typedmkMyValidator :: Scripts.TypedValidator ..." the plutus compiler works fine.

It just happens when its separated over two files and the types are imported. This happens not just with user defined types but with any types declared with the "newtype" variant (AssetClass, Value,...).

Steps to reproduce

Steps to reproduce the behavior:

  1. Write a simple validator Script where the Datum or Redeemer contain a list of types declared with "newtype". Separate type declaration and 'TypedValidator' in two files and import the types to the validator file. (example code in additional context)

2.' cabal build'

  1. See error: -> see at attachments

  2. Move 'MyRedeemer' and 'MyNewtype' to OnChain.hs without changing anything else to the file with the TypedValidator

  3. cabal build

  4. no error

Expected behavior

Should be possible to separate Types, OnChain and OffChain code over different files without plutus compiler issues.

System info (please complete the following information):

Screenshots and attachments

End: Context: Compiling definition of: Types.$fUnsafeFromDataMyRedeemer Context: Compiling expr: Types.$fUnsafeFromDataMyRedeemer Context: Compiling expr: Ledger.Typed.Scripts.Validators.wrapValidator @ Types.MyDatum @ Types.MyRedeemer Types.$fUnsafeFromDataMyDatum Types.$fUnsafeFromDataMyRedeemer Context: Compiling expr at "debugging-0.1.0.0-inplace:OnChain:(57,8)-(57,37)"

Additional context

Code: Types.hs: `{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}

module Types where

import Data.Aeson (FromJSON, ToJSON) import GHC.Generics (Generic) import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup(..), unless) import qualified Prelude (Show,Eq,Ord) import Ledger.Value (AssetClass (..)) import qualified Ledger.Typed.Scripts as Scripts

data MyCustom = MyCustom { data1 :: [AssetClass] -- without list works , data2 :: [BuiltinByteString]
} deriving (Prelude.Show, Generic, FromJSON, ToJSON, Prelude.Eq) PlutusTx.makeIsDataIndexed ''MyCustom [('MyCustom, 0)] PlutusTx.makeLift ''MyCustom

{- Move MyRedeemer and MyNewtype to OnChain.hs without changing anything else -> works -} {- START COMMENT Comment between this to get working example -}

newtype MyNewtype = MyNewtype { unNewType :: Integer } deriving stock (Prelude.Show, Generic) deriving newtype (ToJSON, FromJSON, Prelude.Eq) PlutusTx.makeIsDataIndexed ''MyNewtype [('MyNewtype, 0)] PlutusTx.makeLift ''MyNewtype

data MyRedeemer = RA [MyNewtype] | RB Integer -- Delete the List and make it Single 'MyNewtype' -> it works | -- change RA to 'MyCustom', same error, change data1 to just AssetClass without list -> it works deriving (Prelude.Show, Generic, FromJSON, ToJSON, Prelude.Eq) PlutusTx.makeIsDataIndexed ''MyRedeemer [('RA, 0),('RB, 1)] PlutusTx.makeLift ''MyRedeemer

{- END COMMENT -}

data MyDatum = MyDatum deriving stock (Prelude.Show)
PlutusTx.makeIsDataIndexed ''MyDatum [('MyDatum, 0)] PlutusTx.makeLift ''MyDatum`

OnChain.hs: `{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}

module OnChain where

import Data.Aeson (FromJSON, ToJSON) import GHC.Generics (Generic)

import Ledger hiding (mint, singleton) import PlutusTx.Builtins import qualified Ledger.Typed.Scripts as Scripts import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup(..), unless) import Prelude (Semigroup (..), Show (..), Eq, Ord)

import Types

{- Uncomment for working code newtype MyNewtype = MyNewtype { unNewType :: Integer } deriving stock (Prelude.Show, Generic) deriving newtype (ToJSON, FromJSON, Prelude.Eq) PlutusTx.makeIsDataIndexed ''MyNewtype [('MyNewtype, 0)] PlutusTx.makeLift ''MyNewtype

data MyRedeemer = RA [MyNewtype] | RB Integer -- change RA to 'MyCustom', same error, make data1 just AssetClass without list it works deriving (Prelude.Show, Generic, FromJSON, ToJSON, Prelude.Eq) PlutusTx.makeIsDataIndexed ''MyRedeemer [('RA, 0),('RB, 1)] PlutusTx.makeLift ''MyRedeemer -}

mkMyValidator :: MyDatum -> MyRedeemer -> ScriptContext -> Bool mkMyValidator d r ctx = True

data Dating instance Scripts.ValidatorTypes Dating where type instance DatumType Dating = MyDatum type instance RedeemerType Dating = MyRedeemer

typedmkMyValidator :: Scripts.TypedValidator Dating typedmkMyValidator = Scripts.mkTypedValidator @Dating ($$(PlutusTx.compile [|| mkMyValidator ||]) ) $$(PlutusTx.compile [|| wrap ||]) where wrap = Scripts.wrapValidator @MyDatum @MyRedeemer `

ghost commented 2 years ago

Please try to add the following options to your cabal file:

- `-fno-ignore-interface-pragmas`
- `-fno-omit-interface-pragmas`
- `-fobject-code`

Or state as GHC options in the .hs files:

{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-}
{-# OPTIONS_GHC -fobject-code #-}
Sbcdn commented 2 years ago

Thank you for your reply.

I had the ghc options set already. Added it also to the .hs files but has no effect.

ghost commented 2 years ago

Turned out the missing ghc option was -fno-specialise:

{-# OPTIONS_GHC -fno-specialise #-}
Sbcdn commented 2 years ago

I confirm this does it, thank you ak3n!