Skip to content
This repository has been archived by the owner on Dec 2, 2024. It is now read-only.

PLT-807 Change behavior of MustPayToPubKeyAddress and MustPayToOtherScript #705

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plutus-chain-index-core/src/Plutus/Contract/CardanoAPI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Cardano.Api qualified as C
import Cardano.Api.Shelley qualified as C
import Data.List (sort)
import Ledger qualified as P
import Ledger.Tx.CardanoAPI as Export hiding (fromCardanoTxOut)
import Ledger.Tx.CardanoAPI as Export
import Plutus.ChainIndex.Types (ChainIndexTx (..), ChainIndexTxOut (..), ChainIndexTxOutputs (..), ReferenceScript (..))

fromCardanoBlock :: C.BlockInMode C.CardanoMode -> [ChainIndexTx]
Expand Down
22 changes: 21 additions & 1 deletion plutus-contract/src/Plutus/Contract/Oracle.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,30 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}

{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
{-# OPTIONS_GHC -fno-specialise #-}
{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}

{- Note [Oracle incorrect implementation]

This current Oracle implementation uses the
'Constraints.mustIncludeDatumInTxWithHash' constraint which used to add a datum
in transaction body. However, cardano-ledger enforces a rule (rewording the
rule here..) in which a datum in the transaction body needs to have the same
hash as a datum in one of the transaction's outputs.

However, now that we have fixed the bug in
'Constraints.mustIncludeDatumInTxWithHash' so work with this ledger rule, the
Oracle implementation does not work anymore, and examples in the
plutus-use-cases Haskell package now fail because of this.

Therefore, for now, we will comment out the failing test cases until we rewrite
this Oracle module to work with inline datums instead of datums in the
transaction body. This implies upgrades some of the examples in
`plutus-use-cases` to PlutusV2.
-}
module Plutus.Contract.Oracle(
-- * Signed messages
-- $oracles
Expand Down Expand Up @@ -145,7 +165,7 @@ checkHashConstraints ::
checkHashConstraints SignedMessage{osmMessageHash, osmDatum=Datum dt} =
maybe
(trace "Li" {-"DecodingError"-} $ Left DecodingError)
(\a -> pure (a, Constraints.mustHashDatum osmMessageHash (Datum dt)))
(\a -> pure (a, Constraints.mustIncludeDatumInTxWithHash osmMessageHash (Datum dt)))
(fromBuiltinData dt)

{-# INLINABLE verifySignedMessageConstraints #-}
Expand Down
11 changes: 7 additions & 4 deletions plutus-contract/src/Plutus/Contract/StateMachine.hs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ import Data.Void (Void, absurd)
import GHC.Generics (Generic)
import Ledger (POSIXTime, Slot, TxOutRef, Value)
import Ledger qualified
import Ledger.Constraints (ScriptLookups, TxConstraints, mustMintValueWithRedeemer, mustPayToTheScript,
mustSpendPubKeyOutput, plutusV1MintingPolicy)
import Ledger.Constraints (ScriptLookups, TxConstraints, TxOutDatum (TxOutDatumInTx), mustMintValueWithRedeemer,
mustPayToTheScriptWithDatumInTx, mustSpendPubKeyOutput, plutusV1MintingPolicy)
import Ledger.Constraints.OffChain (UnbalancedTx)
import Ledger.Constraints.OffChain qualified as Constraints
import Ledger.Constraints.TxConstraints (ScriptInputConstraint (ScriptInputConstraint, icRedeemer, icTxOutRef),
Expand Down Expand Up @@ -434,7 +434,10 @@ runInitialiseWith customLookups customConstraints StateMachineClient{scInstance}
mapError (review _SMContractError) $ do
utxo <- ownUtxos
let StateMachineInstance{stateMachine, typedValidator} = scInstance
constraints = mustPayToTheScript initialState (initialValue <> SM.threadTokenValueOrZero scInstance)
constraints =
mustPayToTheScriptWithDatumInTx
initialState
(initialValue <> SM.threadTokenValueOrZero scInstance)
<> foldMap ttConstraints (smThreadToken stateMachine)
<> customConstraints
red = Ledger.Redeemer (PlutusTx.toBuiltinData (Scripts.validatorHash typedValidator, Mint))
Expand Down Expand Up @@ -546,7 +549,7 @@ mkStep client@StateMachineClient{scInstance} input = do
unmint = if isFinal then mustMintValueWithRedeemer red (inv $ SM.threadTokenValueOrZero scInstance) else mempty
outputConstraints =
[ ScriptOutputConstraint
{ ocDatum = stateData newState
{ ocDatum = TxOutDatumInTx $ stateData newState
-- Add the thread token value back to the output
, ocValue = stateValue newState <> SM.threadTokenValueOrZero scInstance
, ocReferenceScriptHash = Nothing
Expand Down
4 changes: 2 additions & 2 deletions plutus-contract/src/Plutus/Contract/StateMachine/OnChain.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import Data.Aeson (FromJSON, ToJSON)
import Data.Void (Void)
import GHC.Generics (Generic)
import Ledger.Constraints (ScriptOutputConstraint (ScriptOutputConstraint, ocDatum, ocReferenceScriptHash, ocValue),
TxConstraints (txOwnOutputs))
TxConstraints (txOwnOutputs), TxOutDatum (TxOutDatumInTx))
import Ledger.Constraints.OnChain.V1 (checkScriptContext)
import Ledger.Typed.Scripts (DatumType, RedeemerType, TypedValidator, ValidatorType, ValidatorTypes, validatorAddress,
validatorHash)
Expand Down Expand Up @@ -131,7 +131,7 @@ mkValidator (StateMachine step isFinal check threadToken) currentState input ptx
newConstraints
{ txOwnOutputs =
[ ScriptOutputConstraint
{ ocDatum = newData
{ ocDatum = TxOutDatumInTx newData
-- Check that the thread token value is still there
, ocValue = newValue <> threadTokenValueInner threadToken (ownHash ptx)
, ocReferenceScriptHash = Nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ import Ledger.Index as Index
import Ledger.Scripts
import Ledger.Slot
import Ledger.Tx hiding (mint)
import Ledger.Tx.CardanoAPI (adaToCardanoValue, fromCardanoTxOut, toCardanoAddressInEra, toCardanoTxOutDatumInTx,
toCardanoTxOutDatumInline)
import Ledger.Tx.CardanoAPI (adaToCardanoValue, fromCardanoTxOutToPV1TxInfoTxOut, toCardanoAddressInEra,
toCardanoTxOutDatumInTx, toCardanoTxOutDatumInline)
import Ledger.Validation qualified as Validation
import Plutus.Contract.Test hiding (not)
import Plutus.Contract.Test.ContractModel.Internal
Expand Down Expand Up @@ -324,7 +324,7 @@ doubleSatisfactionCounterexamples dsc = do
-- For each output in the candidate tx
(idx, out) <- zip [0..] (dsc ^. dsTx . outputs)
-- Is it a pubkeyout?
guard $ isPubKeyOut $ fromCardanoTxOut $ P.getTxOut out
guard $ isPubKeyOut $ fromCardanoTxOutToPV1TxInfoTxOut $ P.getTxOut out
-- Whose key is not in the signatories?
key <- maybeToList . txOutPubKey $ out
let signatories = dsc ^. dsTx . signatures . to Map.keys
Expand Down
2 changes: 1 addition & 1 deletion plutus-contract/test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ main = defaultMain tests
tests :: TestTree
tests = testGroup "plutus-contract" [
Spec.Contract.tests,
Spec.Contract.TxConstraints.tests,
Spec.Emulator.tests,
Spec.State.tests,
Spec.Rows.tests,
Spec.ThreadToken.tests,
Spec.Contract.TxConstraints.tests,
Spec.TxConstraints.MustIncludeDatum.tests,
Spec.TxConstraints.MustMint.tests,
Spec.TxConstraints.MustPayToOtherScript.tests,
Expand Down
53 changes: 42 additions & 11 deletions plutus-contract/test/Spec/Balancing.hs
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,40 @@ balanceTxnMinAda =

contract :: Contract () EmptySchema ContractError ()
contract = do
let constraints1 = L.Constraints.mustPayToOtherScript vHash unitDatum (Value.scale 100 ff <> Ada.toValue Ledger.minAdaTxOut)
let constraints1 =
L.Constraints.mustPayToOtherScriptWithDatumInTx
vHash
unitDatum
(Value.scale 100 ff <> Ada.toValue Ledger.minAdaTxOut)
<> L.Constraints.mustIncludeDatumInTx unitDatum
utx1 = either (error . show) id $ L.Constraints.mkTx @Void mempty constraints1
submitTxConfirmed utx1
utxo <- utxosAt someAddress
let txOutRef = head (Map.keys utxo)
constraints2 = L.Constraints.mustSpendScriptOutput txOutRef unitRedeemer
<> L.Constraints.mustPayToOtherScript vHash unitDatum (Value.scale 200 ee)
lookups2 = L.Constraints.unspentOutputs utxo <> L.Constraints.plutusV1OtherScript someValidator
utx2 <- Con.adjustUnbalancedTx $ either (error . show) id $ L.Constraints.mkTx @Void lookups2 constraints2
constraints2 =
L.Constraints.mustSpendScriptOutput txOutRef unitRedeemer
<> L.Constraints.mustPayToOtherScriptWithDatumInTx
vHash
unitDatum
(Value.scale 200 ee)
<> L.Constraints.mustIncludeDatumInTx unitDatum
lookups2 =
L.Constraints.unspentOutputs utxo
<> L.Constraints.plutusV1OtherScript someValidator
utx2 <- Con.adjustUnbalancedTx
$ either (error . show) id
$ L.Constraints.mkTx @Void lookups2 constraints2
submitTxConfirmed utx2

trace = do
void $ Trace.activateContractWallet w1 contract
void $ Trace.waitNSlots 2

in checkPredicateOptions options "balancing doesn't create outputs with no Ada" (assertValidatedTransactionCount 2) (void trace)
in checkPredicateOptions
options
"balancing doesn't create outputs with no Ada"
(assertValidatedTransactionCount 2)
(void trace)

balanceTxnMinAda2 :: TestTree
balanceTxnMinAda2 =
Expand All @@ -76,14 +94,24 @@ balanceTxnMinAda2 =
& changeInitialWalletValue w1 (<> vA 1 <> vB 2)
vHash = Scripts.validatorHash someValidator
payToWallet w = L.Constraints.mustPayToPubKey (EM.mockWalletPaymentPubKeyHash w)
mkTx lookups constraints = Con.adjustUnbalancedTx . either (error . show) id $ L.Constraints.mkTx @Void lookups constraints
mkTx lookups constraints =
Con.adjustUnbalancedTx . either (error . show) id
$ L.Constraints.mkTx @Void lookups constraints

setupContract :: Contract () EmptySchema ContractError ()
setupContract = do
-- Make sure there is a utxo with 1 A, 1 B, and 4 ada at w2
submitTxConfirmed =<< mkTx mempty (payToWallet w2 (vA 1 <> vB 1 <> Value.scale 2 (Ada.toValue Ledger.minAdaTxOut)))
submitTxConfirmed
=<< mkTx mempty
(payToWallet w2 ( vA 1
<> vB 1
<> Value.scale 2 (Ada.toValue Ledger.minAdaTxOut)
))
-- Make sure there is a UTxO with 1 B and datum () at the script
submitTxConfirmed =<< mkTx mempty (L.Constraints.mustPayToOtherScript vHash unitDatum (vB 1))
submitTxConfirmed
=<< mkTx mempty ( L.Constraints.mustPayToOtherScriptWithDatumInTx vHash unitDatum (vB 1)
<> L.Constraints.mustIncludeDatumInTx unitDatum
)
-- utxo0 @ wallet2 = 1 A, 1 B, 4 Ada
-- utxo1 @ script = 1 B, 2 Ada

Expand All @@ -96,9 +124,12 @@ balanceTxnMinAda2 =
lookups = L.Constraints.unspentOutputs utxos
<> L.Constraints.plutusV1OtherScript someValidator
<> L.Constraints.plutusV1MintingPolicy mps
datum = Datum $ PlutusTx.toBuiltinData (0 :: Integer)
constraints = L.Constraints.mustSpendScriptOutput txOutRef unitRedeemer -- spend utxo1
<> L.Constraints.mustPayToOtherScript vHash unitDatum (vB 1) -- 2 ada and 1 B to script
<> L.Constraints.mustPayToOtherScript vHash (Datum $ PlutusTx.toBuiltinData (0 :: Integer)) (vB 1) -- 2 ada and 1 B to script (different datum)
<> L.Constraints.mustPayToOtherScriptWithDatumInTx vHash unitDatum (vB 1) -- 2 ada and 1 B to script
<> L.Constraints.mustPayToOtherScriptWithDatumInTx vHash datum (vB 1) -- 2 ada and 1 B to script (different datum)
<> L.Constraints.mustIncludeDatumInTx unitDatum
<> L.Constraints.mustIncludeDatumInTx datum
<> L.Constraints.mustMintValue (vL 1) -- 1 L and 2 ada to wallet2
submitTxConfirmed =<< mkTx lookups constraints

Expand Down
32 changes: 24 additions & 8 deletions plutus-contract/test/Spec/Contract/TxConstraints.hs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ mustReferenceOutputV1ConTest = do
let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos
vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress
lookups = TC.unspentOutputs utxos
tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
datum = Datum $ PlutusTx.toBuiltinData utxoRef
tx = TC.mustIncludeDatumInTx datum
<> TC.mustPayToOtherScriptWithDatumInTx vh datum (Ada.adaValueOf 5)
<> TC.mustSpendPubKeyOutput utxoRefForBalance1
mkTxConstraints @Void lookups tx >>= submitTxConfirmed

Expand All @@ -176,7 +178,9 @@ mustReferenceOutputTxV1ConTest = do
let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos
vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV1ValidatorAddress
lookups = Tx.Constraints.unspentOutputs utxos
tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
datum = Datum $ PlutusTx.toBuiltinData utxoRef
tx = Tx.Constraints.mustPayToOtherScriptWithDatumInTx vh datum (Ada.adaValueOf 5)
<> Tx.Constraints.mustIncludeDatumInTx datum
<> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1
<> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1
submitTxConfirmed $ mkTx lookups tx
Expand Down Expand Up @@ -221,7 +225,9 @@ mustReferenceOutputV2ConTest = do
let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos
vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress
lookups = TC.unspentOutputs utxos
tx = TC.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
datum = Datum $ PlutusTx.toBuiltinData utxoRef
tx = TC.mustPayToOtherScriptWithDatumInTx vh datum (Ada.adaValueOf 5)
<> TC.mustIncludeDatumInTx datum
<> TC.mustSpendPubKeyOutput utxoRefForBalance1
mkTxConstraints @Void lookups tx >>= submitTxConfirmed

Expand All @@ -245,7 +251,9 @@ mustReferenceOutputTxV2ConTest = do
let ((utxoRef, utxo), (utxoRefForBalance1, _), (utxoRefForBalance2, _)) = get3 $ Map.toList utxos
vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress
lookups = Tx.Constraints.unspentOutputs utxos
tx = Tx.Constraints.mustPayToOtherScript vh (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
datum = Datum $ PlutusTx.toBuiltinData utxoRef
tx = Tx.Constraints.mustPayToOtherScriptWithDatumInTx vh datum (Ada.adaValueOf 5)
<> Tx.Constraints.mustIncludeDatumInTx datum
<> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1
<> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1
submitTxConfirmed $ mkTx lookups tx
Expand Down Expand Up @@ -276,12 +284,16 @@ mustSpendScriptOutputWithReferenceV2ConTest = do
ValidatorHash vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress
lookups = TC.unspentOutputs utxos
<> TC.plutusV2OtherScript mustReferenceOutputV2Validator
tx = TC.mustPayToOtherScript (ValidatorHash vh) (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
tx = TC.mustPayToOtherScriptWithDatumInTx
(ValidatorHash vh)
(Datum $ PlutusTx.toBuiltinData utxoRef)
(Ada.adaValueOf 5)
<> TC.mustSpendPubKeyOutput utxoRefForBalance1
<> TC.mustPayToAddressWithReferenceScript
myAddr
(ScriptHash vh)
Nothing (Ada.adaValueOf 25)
Nothing
(Ada.adaValueOf 30)
mkTxConstraints @Void lookups tx >>= submitTxConfirmed

-- Trying to unlock the Ada in the script address
Expand All @@ -306,13 +318,17 @@ mustSpendScriptOutputWithReferenceTxV2ConTest = do
ValidatorHash vh = fromJust $ Addr.toValidatorHash mustReferenceOutputV2ValidatorAddress
lookups = Tx.Constraints.unspentOutputs utxos
<> Tx.Constraints.plutusV2OtherScript mustReferenceOutputV2Validator
tx = Tx.Constraints.mustPayToOtherScript (ValidatorHash vh) (Datum $ PlutusTx.toBuiltinData utxoRef) (Ada.adaValueOf 5)
tx = Tx.Constraints.mustPayToOtherScriptWithDatumInTx
(ValidatorHash vh)
(Datum $ PlutusTx.toBuiltinData utxoRef)
(Ada.adaValueOf 5)
<> Tx.Constraints.mustSpendPubKeyOutput utxoRefForBalance1
<> Tx.Constraints.mustUseOutputAsCollateral utxoRefForBalance1
<> Tx.Constraints.mustPayToAddressWithReferenceScript
myAddr
(ScriptHash vh)
Nothing (Ada.adaValueOf 25)
Nothing
(Ada.adaValueOf 30)
submitTxConfirmed $ mkTx lookups tx

-- Trying to unlock the Ada in the script address
Expand Down
6 changes: 4 additions & 2 deletions plutus-contract/test/Spec/ErrorChecking.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Data.Row
import Test.Tasty

import Ledger.Ada qualified as Ada
import Ledger.Constraints (collectFromTheScript, mustPayToOtherScript)
import Ledger.Constraints (collectFromTheScript, mustIncludeDatumInTx, mustPayToOtherScriptWithDatumInTx)
import Ledger.Tx (getCardanoTxId)
import Ledger.Typed.Scripts qualified as Scripts hiding (validatorHash)
import Plutus.Contract as Contract
Expand Down Expand Up @@ -141,7 +141,9 @@ contract = selectList [failFalseC, failHeadNilC, divZeroC, divZeroTraceC, succes
run validator = void $ do
let addr = mkValidatorAddress (validatorScript validator)
hash = validatorHash (validatorScript validator)
tx = mustPayToOtherScript hash (Datum $ toBuiltinData ()) (Ada.adaValueOf 10)
datum = Datum $ toBuiltinData ()
tx = mustPayToOtherScriptWithDatumInTx hash datum (Ada.adaValueOf 10)
<> mustIncludeDatumInTx datum
r <- submitTx tx
awaitTxConfirmed (getCardanoTxId r)
utxos <- utxosAt addr
Expand Down
Loading