Skip to content

Commit

Permalink
[Plinth] Ban using 'toBuiltin' and 'fromBuiltin' (#6342)
Browse files Browse the repository at this point in the history
It used to be possible to use `toBuiltin`/`fromBuiltin` within a smart contract, but this is no longer the case, but this isn't obvious to the users as they already have code with `toBuiltin`/`fromBuiltin` that now just misbehaves instead of throwing a type error or breaking compilation some other way. This fixes the problem by throwing on any usage of `toBuiltin`/`fromBuiltin` with a suggestion to use `toOpaque`/`fromOpaque` instead.
  • Loading branch information
effectfully authored Jul 26, 2024
1 parent d510d24 commit bfac69f
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 23 deletions.
8 changes: 8 additions & 0 deletions plutus-tx-plugin/src/PlutusTx/Compiler/Expr.hs
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,8 @@ compileExpr e = traceCompilation 2 ("Compiling expr:" GHC.<+> GHC.ppr e) $ do
(Just t1, Just t2) -> pure (GHC.getName t1, GHC.getName t2)
_ -> throwPlain $ CompilationError "No info for ByteString builtin"

useToOpaqueName <- GHC.getName <$> getThing 'Builtins.useToOpaque
useFromOpaqueName <- GHC.getName <$> getThing 'Builtins.useFromOpaque
boolOperatorOr <- GHC.getName <$> getThing '(PlutusTx.Bool.||)
boolOperatorAnd <- GHC.getName <$> getThing '(PlutusTx.Bool.&&)
case e of
Expand Down Expand Up @@ -775,6 +777,12 @@ compileExpr e = traceCompilation 2 ("Compiling expr:" GHC.<+> GHC.ppr e) $ do
-- <error func> <overall type> <message>
GHC.Var (isErrorId -> True) `GHC.App` GHC.Type t `GHC.App` _ ->
PIR.TyInst annMayInline <$> errorFunc <*> compileTypeNorm t
GHC.Var n
| GHC.getName n == useToOpaqueName ->
throwPlain $ UnsupportedError "It is no longer possible to use 'toBuiltin' with a script, use 'toOpaque' instead"
GHC.Var n
| GHC.getName n == useFromOpaqueName ->
throwPlain $ UnsupportedError "It is no longer possible to use 'fromBuiltin' with a script, use 'fromOpaque' instead"
-- See Note [Uses of Eq]
GHC.Var n
| GHC.getName n == GHC.eqName ->
Expand Down
3 changes: 3 additions & 0 deletions plutus-tx-plugin/src/PlutusTx/Plugin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module PlutusTx.Plugin (plugin, plc) where
import Data.Bifunctor
import PlutusPrelude
import PlutusTx.Bool ((&&), (||))
import PlutusTx.Builtins.HasBuiltin (useFromOpaque, useToOpaque)
import PlutusTx.Code
import PlutusTx.Compiler.Builtins
import PlutusTx.Compiler.Error
Expand Down Expand Up @@ -405,6 +406,8 @@ compileMarkedExpr locStr codeTy origE = do
, 'GHC.Num.Integer.integerNegate
, '(PlutusTx.Bool.&&)
, '(PlutusTx.Bool.||)
, 'useToOpaque
, 'useFromOpaque
]
modBreaks <- asks pcModuleModBreaks
let coverage = CoverageOpts . Set.fromList $
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: Unsupported feature: It is no longer possible to use 'fromBuiltin' with a script, use 'fromOpaque' instead
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error: Unsupported feature: It is no longer possible to use 'toBuiltin' with a script, use 'toOpaque' instead
8 changes: 8 additions & 0 deletions plutus-tx-plugin/test/Plugin/Errors/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ errors = testNested "Errors" . pure $ testNestedGhc
, goldenUPlc "rangeEnumFromThenTo" rangeEnumFromThenTo
, goldenUPlc "rangeEnumFrom" rangeEnumFrom
, goldenUPlc "rangeEnumFromThen" rangeEnumFromThen
, goldenUPlc "toBuiltinUsed" toBuiltinUsed
, goldenUPlc "fromBuiltinUsed" fromBuiltinUsed
]

machInt :: CompiledCode Int
Expand Down Expand Up @@ -114,3 +116,9 @@ rangeEnumFrom = plc (Proxy @"rangeEnumFrom") [1..]

rangeEnumFromThen :: CompiledCode [Integer]
rangeEnumFromThen = plc (Proxy @"rangeEnumFromThen") [1,5..]

toBuiltinUsed :: CompiledCode (Integer -> Integer)
toBuiltinUsed = plc (Proxy @"toBuiltinUsed") Builtins.toBuiltin

fromBuiltinUsed :: CompiledCode (Integer -> Integer)
fromBuiltinUsed = plc (Proxy @"fromBuiltinUsed") Builtins.fromBuiltin
2 changes: 2 additions & 0 deletions plutus-tx/src/PlutusTx/Builtins.hs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ module PlutusTx.Builtins (
-- * Conversions
, fromOpaque
, toOpaque
, useToOpaque
, useFromOpaque
, fromBuiltin
, toBuiltin
-- * Logical
Expand Down
38 changes: 26 additions & 12 deletions plutus-tx/src/PlutusTx/Builtins/HasBuiltin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ import Data.ByteString (ByteString)
import Data.Kind qualified as GHC
import Data.Text (Text)

{- Note [useToOpaque and useFromOpaque]
It used to be possible to use 'toBuiltin'/'fromBuiltin' within a smart contract, but this is no
longer the case, hence we throw a compilation error suggesting to use 'toOpaque'/'fromOpaque'
instead.
-}

useToOpaque :: a -> a
useToOpaque x = x
{-# OPAQUE useToOpaque #-}

useFromOpaque :: a -> a
useFromOpaque x = x
{-# OPAQUE useFromOpaque #-}

-- Also see Note [Built-in types and their Haskell counterparts].
-- | A class for converting values of Haskell-defined built-in types to their Plutus Tx
-- counterparts.
Expand All @@ -37,42 +51,42 @@ class HasToBuiltin (FromBuiltin arep) => HasFromBuiltin arep where

instance HasToBuiltin Integer where
type ToBuiltin Integer = BuiltinInteger
toBuiltin = id
toBuiltin = useToOpaque id
instance HasFromBuiltin BuiltinInteger where
type FromBuiltin BuiltinInteger = Integer
fromBuiltin = id
fromBuiltin = useFromOpaque id

instance HasToBuiltin ByteString where
type ToBuiltin ByteString = BuiltinByteString
toBuiltin = BuiltinByteString
toBuiltin = useToOpaque BuiltinByteString
instance HasFromBuiltin BuiltinByteString where
type FromBuiltin BuiltinByteString = ByteString
fromBuiltin (BuiltinByteString b) = b
fromBuiltin = useFromOpaque $ \(BuiltinByteString b) -> b

instance HasToBuiltin Text where
type ToBuiltin Text = BuiltinString
toBuiltin = BuiltinString
toBuiltin = useToOpaque BuiltinString
instance HasFromBuiltin BuiltinString where
type FromBuiltin BuiltinString = Text
fromBuiltin (BuiltinString t) = t

instance HasToBuiltin () where
type ToBuiltin () = BuiltinUnit
toBuiltin = BuiltinUnit
toBuiltin = useToOpaque BuiltinUnit
instance HasFromBuiltin BuiltinUnit where
type FromBuiltin BuiltinUnit = ()
fromBuiltin (BuiltinUnit u) = u

instance HasToBuiltin Bool where
type ToBuiltin Bool = BuiltinBool
toBuiltin = BuiltinBool
toBuiltin = useToOpaque BuiltinBool
instance HasFromBuiltin BuiltinBool where
type FromBuiltin BuiltinBool = Bool
fromBuiltin (BuiltinBool b) = b

instance HasToBuiltin a => HasToBuiltin [a] where
type ToBuiltin [a] = BuiltinList (ToBuiltin a)
toBuiltin = BuiltinList . map toBuiltin
toBuiltin = useToOpaque BuiltinList . map toBuiltin
instance HasFromBuiltin a => HasFromBuiltin (BuiltinList a) where
type FromBuiltin (BuiltinList a) = [FromBuiltin a]
fromBuiltin (BuiltinList xs) = map fromBuiltin xs
Expand All @@ -86,28 +100,28 @@ instance (HasFromBuiltin a, HasFromBuiltin b) => HasFromBuiltin (BuiltinPair a b

instance HasToBuiltin Data where
type ToBuiltin Data = BuiltinData
toBuiltin = BuiltinData
toBuiltin = useToOpaque BuiltinData
instance HasFromBuiltin BuiltinData where
type FromBuiltin BuiltinData = Data
fromBuiltin (BuiltinData t) = t

instance HasToBuiltin BLS12_381.G1.Element where
type ToBuiltin BLS12_381.G1.Element = BuiltinBLS12_381_G1_Element
toBuiltin = BuiltinBLS12_381_G1_Element
toBuiltin = useToOpaque BuiltinBLS12_381_G1_Element
instance HasFromBuiltin BuiltinBLS12_381_G1_Element where
type FromBuiltin BuiltinBLS12_381_G1_Element = BLS12_381.G1.Element
fromBuiltin (BuiltinBLS12_381_G1_Element a) = a

instance HasToBuiltin BLS12_381.G2.Element where
type ToBuiltin BLS12_381.G2.Element = BuiltinBLS12_381_G2_Element
toBuiltin = BuiltinBLS12_381_G2_Element
toBuiltin = useToOpaque BuiltinBLS12_381_G2_Element
instance HasFromBuiltin BuiltinBLS12_381_G2_Element where
type FromBuiltin BuiltinBLS12_381_G2_Element = BLS12_381.G2.Element
fromBuiltin (BuiltinBLS12_381_G2_Element a) = a

instance HasToBuiltin BLS12_381.Pairing.MlResult where
type ToBuiltin BLS12_381.Pairing.MlResult = BuiltinBLS12_381_MlResult
toBuiltin = BuiltinBLS12_381_MlResult
toBuiltin = useToOpaque BuiltinBLS12_381_MlResult
instance HasFromBuiltin BuiltinBLS12_381_MlResult where
type FromBuiltin BuiltinBLS12_381_MlResult = BLS12_381.Pairing.MlResult
fromBuiltin (BuiltinBLS12_381_MlResult a) = a
14 changes: 3 additions & 11 deletions plutus-tx/src/PlutusTx/IsData/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
module PlutusTx.IsData.Class where

import Prelude qualified as Haskell (Either (..), Int, error)
import Prelude qualified as Haskell (Int, error)

import PlutusCore.Crypto.BLS12_381.G1 qualified as BLS12_381.G1
import PlutusCore.Crypto.BLS12_381.G2 qualified as BLS12_381.G2
import PlutusCore.Data qualified as PLC
import PlutusTx.Base
import PlutusTx.Builtins as Builtins
Expand Down Expand Up @@ -159,10 +157,7 @@ instance FromData Builtins.BuiltinBLS12_381_G1_Element where
fromBuiltinData d =
case fromBuiltinData d of
Nothing -> Nothing
Just (BI.BuiltinByteString bs) ->
case BLS12_381.G1.uncompress bs of
Haskell.Left _ -> Nothing
Haskell.Right g -> Just $ toBuiltin g
Just bs -> Just $ bls12_381_G1_uncompress bs
instance UnsafeFromData Builtins.BuiltinBLS12_381_G1_Element where
{-# INLINABLE unsafeFromBuiltinData #-}
unsafeFromBuiltinData = Builtins.bls12_381_G1_uncompress . unsafeFromBuiltinData
Expand All @@ -175,10 +170,7 @@ instance FromData Builtins.BuiltinBLS12_381_G2_Element where
fromBuiltinData d =
case fromBuiltinData d of
Nothing -> Nothing
Just (BI.BuiltinByteString bs) ->
case BLS12_381.G2.uncompress bs of
Haskell.Left _ -> Nothing
Haskell.Right g -> Just $ toBuiltin g
Just bs -> Just $ bls12_381_G2_uncompress bs
instance UnsafeFromData Builtins.BuiltinBLS12_381_G2_Element where
{-# INLINABLE unsafeFromBuiltinData #-}
unsafeFromBuiltinData = Builtins.bls12_381_G2_uncompress . unsafeFromBuiltinData
Expand Down

0 comments on commit bfac69f

Please sign in to comment.