Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot compare TokenName in Validator #3254

Closed
tdiesler opened this issue May 24, 2021 · 10 comments · Fixed by #3269
Closed

Cannot compare TokenName in Validator #3254

tdiesler opened this issue May 24, 2021 · 10 comments · Fixed by #3269
Labels

Comments

@tdiesler
Copy link

Area

[] Plutus Foundation Related to the GHC plugin, Haskell-to-Plutus compiler, on-chain code

Summary

Simple equality of a token name does not compile

image

GHC Core to PLC plugin: E043:Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable GHC.Magic.runRW#
            No unfolding
Context: Compiling expr: GHC.Magic.runRW#
Context: Compiling expr: GHC.Magic.runRW#
                           @ ('GHC.Types.TupleRep
                                '[ 'GHC.Types.TupleRep '[], 'GHC.Types.LiftedRep])
Context: Compiling expr: GHC.Magic.runRW#
                           @ ('GHC.Types.TupleRep
                                '[ 'GHC.Types.TupleRep '[], 'GHC.Types.LiftedRep])
                           @ (# GHC.Prim.State# GHC.Prim.RealWorld, Data.Text.Internal.Text #)
Context: Compiling expr: GHC.Magic.runRW#
                           @ ('GHC.Types.TupleRep
                                '[ 'GHC.Types.TupleRep '[], 'GHC.Types.LiftedRep])
                           @ (# GHC.Prim.State# GHC.Prim.RealWorld, Data.Text.Internal.Text #)
                           (\ (s1 [Occ=Once, OS=OneShot]
                                 :: GHC.Prim.State# GHC.Prim.RealWorld) ->
                              case GHC.Prim.newByteArray# @ GHC.Prim.RealWorld 10# s1 of
                              { (# ipv [Occ=Once], ipv1 [Occ=Once] #) ->
                              Plutus.V1.Ledger.Value.$fIsStringTokenName3
                                (Data.Text.Array.MArray @ GHC.Prim.RealWorld ipv1)
                                Plutus.V1.Ledger.Value.$fIsStringTokenName2
                                dt
                                Plutus.V1.Ledger.Value.$fFromJSONAssetClass2
                                ipv
                              })

System info (please complete the following information):

@tdiesler tdiesler added the bug label May 24, 2021
@tdiesler
Copy link
Author

tdiesler commented May 24, 2021

I'm generally having a hard time comparing variants of string

-- GHC Core to PLC plugin: E043:Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable GHC.List.$wlenAcc
("abc" :: ByteString) == ("abc" :: ByteString)

-- No instance for (Eq Char) arising from a use of ‘==’
("abc" :: String) == ("abc" :: String)

-- No instance for (Eq Text) arising from a use of ‘==’
("abc" :: Text) == ("abc" :: Text)

@ghost
Copy link

ghost commented May 25, 2021

  1. Please, make sure that you use PlutusTx.== instead of Prelude.==.

TokenName is a newtype around Builtins.ByteString which has PlutusTx.Eq instance.

-- GHC Core to PLC plugin: E043:Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable GHC.List.$wlenAcc
("abc" :: ByteString) == ("abc" :: ByteString)

This error happens because ByteString literals are not supported yet (#3156). Will be fixed in the future.

-- No instance for (Eq Char) arising from a use of ‘==’
("abc" :: String) == ("abc" :: String)

The error happens here because there is no instance PlutusTx.Eq for Prelude.Char since String = [Char] in Prelude. And there is no way to compare two String's yet. It should be implemented in the future. Thanks for raising the priority of that!

-- No instance for (Eq Text) arising from a use of ‘==’
("abc" :: Text) == ("abc" :: Text)

Yeah, Text is unsupported (there is no instance for PlutusTx.Eq class. Only ByteString and String.

@tdiesler
Copy link
Author

I have ...

import qualified PlutusTx               as PlutusTx
import           PlutusTx.Prelude       hiding (Semigroup(..))
import           Prelude                (Semigroup (..))

and later ...

image

This gives me ...

image

Could you perhaps show me how to construct a TokenName from a String and an Integer and then compare that to the TokenName that the caller provided?

The code is here ...
https://github.com/tdiesler/plutus-pioneer-program/blob/pl3246b/code/payout/src/Astor/Payout.hs#L287

@ghost
Copy link

ghost commented May 26, 2021

== is exported by PlutusTx.Prelude, not PlutusTx.

So it should be:

import qualified PlutusTx.Prelude       as Plutus
import           Prelude                (Semigroup (..))

...

Plutus.== 

TokenName is constructed by calling TokenName constructor (from Ledger module) applied to ByteString:

exptn :: TokenName
exptn = TokenName "Astor260"

"Astor260" here should be ByteString.

Could you perhaps show me how to construct a TokenName from a String and an Integer and then compare that to the TokenName that the caller provided?

It's not possible yet unfortunately. There is no way to transform integer into String or ByteString.

You may try to declare a pair (ByteString, Integer) and compare tuples.

@ghost ghost mentioned this issue May 26, 2021
11 tasks
@tdiesler
Copy link
Author

Thanks. Could I perhaps extract the Integer suffix from the caller provided TokenName? For example, everything after the first five bytes should read as an Integer.

@ghost
Copy link

ghost commented May 26, 2021

Well, there is dropByteString that allows to get the suffix as a ByteString. And then you can compare it to other ByteStrings.

@tdiesler
Copy link
Author

I have a 260 :: Integer and need to validate that the caller provides an "Astor260" :: TokenName.

I would either need to turn the TokenName suffix into an Integer and compare the two Integers or the Integer that I have into a BytesString and then compare those. From what we said above, it is not (yet) possible construct a TokenName from a String prefix plus Integer - like this ("Astor" ++ (show 260)) :: TokenName so that I could simple compare two TokenNames.

How would you validate the given TokenName?

@ghost
Copy link

ghost commented May 26, 2021

Again, it's not possible to convert Integer to any string yet in on-chain code.

You can take the suffix and parse it for example:

let suffix = dropByteString 5 "Astor260" in
case suffix of
  "260" -> handleTheSituationWhenSuffixIs260
  _ -> ...

@tdiesler
Copy link
Author

How about this ...

image

I can construct the token name from String+Integer in off-chain code and put it in the Datum. In on-chain code, I now have both, the epoch Integer and the associated TokenName (which I cannot construct in on-chain code).

@ghost ghost self-assigned this May 27, 2021
@ghost ghost linked a pull request May 27, 2021 that will close this issue
11 tasks
@tdiesler
Copy link
Author

tdiesler commented Jun 1, 2021

merci

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant