1

Supposed I have a validator below, checking only if the output value is locked by the same script.

{-# INLINEABLE mkValidator #-}
mkValidator :: TestingParam -> TestingDatum -> TestingRedeemer -> ScriptContext -> Bool
mkValidator param _ red ctx = case red of
  (MergeScript anotherParam) -> 
    traceIfFalse "Script provided is incorrect" (valueLockedBy info (valHash anotherParam) == txOutValue ownInput)
  _ -> False
  where
    info :: TxInfo
    info = scriptContextTxInfo ctx

    ownInput :: TxOut
    ownInput = case findOwnInput ctx of
      Nothing -> traceError "input missing"
      Just i -> txInInfoResolved i

{-# INLINABLE typedValidator #-}
typedValidator :: TestingParam -> Scripts.TypedValidator TestingScript
typedValidator param =
  Scripts.mkTypedValidator @TestingScript
    ($$(PlutusTx.compile [||mkValidator||]) `PlutusTx.applyCode` PlutusTx.liftCode param)
    $$(PlutusTx.compile [||wrap||])
  where
    wrap = Scripts.wrapValidator @TestingDatum @TestingRedeemer

{-# INLINABLE validator #-}
validator :: TestingParam -> Validator
validator = Scripts.validatorScript . typedValidator

{-# INLINABLE valHash #-}
valHash :: TestingParam -> Ledger.ValidatorHash
valHash = Scripts.validatorHash . typedValidator

However, it then throws the error GHC Core to PLC plugin: E043:Error: Reference to a name which is not a local, a builtin, or an external INLINABLE function: Variable OtherScripts.Testing.ReferenceTesting.valHash.

Another similar issue with supplying minting policy here: Using `curSymbol` function in Validator script

Looked at several sources and stuck with this issue for months. Can someone advises me if it is a dead end current Plutus ability?

If so, happy to see if someone is interested in drafting a CIP for this together, since allowing to use mkValidator or mkMintingPolicy script externally allows another level of scripts composibility which I think is essential for Cardano smart contract to get into mainstream. Also, this would enable scripts to be composed more secured as validator could know the identity of other scripts they are interacting with, instead of just hardcoding-supplying a validator hash externally.

3 Answers 3

3

In this case, when compiling your validator, compiler is trying to compute a value (which is only available after successfully compiled your validator) to complete compiling your validator, thus, it's impossible case.

Your validator is parameterized validator so with each different parameter, it's different validator with different validator hash.

If you want to get outputs of the same validator with same parameter then, that's same validator with same validator hash so there is a getContinuingOutputs function you can use or findContinuingOutputs if you are only interested in amount. Also ownHash is available for getting the validator hash within the same validator.

If it's the case that you want to check an output is locked by the same validator but with different parameter, then it's no longer same validator, it's a completely different validator with different validator hash even if the source code is the same. In this case, you probably might want to provide validator hash directly to the validator via datum or redeemer rather than providing the different parameter which is not possible to compute hash from.

3
  • I am looking for checking whether some value is correctly paid to "certain parameterized scripts" while I dont know the script address beforehand. Certainly I could remove to parameter field to use getContinuingOutputs entirely, but sometimes I also want to enable it to look at other validator and minting script as well. Any thought any workaround instead of using above code to compute? Sep 7, 2022 at 2:21
  • If you want to check for "another validator" and have the functionality at hands for future cases, i would suggest you to dynamically provide the validator hash to the validator either via datum or via redeemer. Sep 7, 2022 at 6:53
  • About computing script's hash (minting script or validator) on chain, i am not sure if it's possible. Let's say, that, it's possible to compute hash on chain from script's binary. How are you going to put binary in the validator? Hard code it? or again, via datum or redeemer? We now came back to the first step. If binary can be hard-coded, why not the hash of it? Same question for datum and redeemer. Sep 7, 2022 at 6:59
1

Script.validatorHash can not be compiled to Plutus Core (probably for good reason, as it would've resulted in much larger on-chain scripts).

As Erik mentioned, if you only need the hash of your current validator, ownHash is the answer. But if you want to recreate the validator hash of another script on the fly, that's not possible.

A typical solution is to provide this desired validator hash as a parameter to your current script, and therefore make it "aware" of your other script.

2
  • Is there any other work-around to calculate script address onchain? Even if others have provided the validator hash in, checking on it seems necessary to prevent bad actors on exploiting the script Sep 7, 2022 at 2:19
  • Generating a script hash from parameters is a somewhat resource intensive task, so it may not even be possible to achieve that within the 16KB transaction size constraint. This depends on your contract of course, but one solution might be for your script to demand the presence of a known asset (i.e. native token) from the arbitrary script you're trying to check. This has the additional benefit of making sure that said script is in fact capable of spending its UTxOs.
    – keyanm
    Sep 8, 2022 at 1:51
0

I suspect that this might actually be a GHC Template Haskell (TH) staging error. My understanding is that when you use TH in a file, it must all be expanded (TH is basically a macro expansion system) on the first TH evaluation pass.

Your function valHash calls typedValidator which includes TH functionality and then you are tying to call that within mkValidator which also uses TH. That is why I think you are actually hitting a staging error due to the implicit recursion of mkValidate -> valHash -> typeValidator -> mkValidate.

The current solution (not really that nice IMO) is to provide (ie hard code) the hash itself to mkValidate. You can probably also write a test to validate that the supplied hash is the same as the actual hash provided by TH.

Update: Apparently there is an ownHash in the Plutus libs that will give you the hash of a validator inside the same validator. I have not tried it.

1
  • How about I want to calculate the script address on chain to conduct the checking? Simply submitting a validator hash in provides loophole for bad actors to exploit. Is it somewhat impossible as mentioned by @KeyanM & @Tuvshintsenguun? Sep 7, 2022 at 2:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.