Skip to content

Commit

Permalink
Use '[TxIn]' instead of 'Set TxIn' in 'data Tx' (#623)
Browse files Browse the repository at this point in the history
* [plutus-ledger]: Use '[TxIn]' instead of 'Set TxIn' in 'data Tx'.
* Add a property test to check Ord instances of TxIn.
* Sort the inputs in fromOnChainTx
* Sort the inputs in `Emulator.Wallet`
* Fix the review notes and the problem with getInput in StateMachine tests
  • Loading branch information
Evgenii Akentev authored Aug 1, 2022
1 parent cadf74c commit 98ad189
Show file tree
Hide file tree
Showing 28 changed files with 238 additions and 209 deletions.
13 changes: 6 additions & 7 deletions plutus-chain-index-core/src/Plutus/ChainIndex/Tx.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module Plutus.ChainIndex.Tx(
) where

import Cardano.Api (NetworkId)
import Data.List (sort)
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Set (Set)
Expand Down Expand Up @@ -89,7 +90,7 @@ fromOnChainTx networkId = \case
let (validatorHashes, otherDataHashes, redeemers) = validators txInputs in
ChainIndexTx
{ _citxTxId = txId tx
, _citxInputs = Set.toList txInputs
, _citxInputs = txInputs
, _citxOutputs = case traverse (toCardanoTxOut networkId toCardanoTxOutDatumHash) txOutputs of
Right txs -> either (const InvalidTx) ValidTx $ traverse fromCardanoTxOut txs
Left _ -> InvalidTx
Expand All @@ -107,7 +108,7 @@ fromOnChainTx networkId = \case
let (validatorHashes, otherDataHashes, redeemers) = validators txInputs in
ChainIndexTx
{ _citxTxId = txId tx
, _citxInputs = Set.toList txCollateral
, _citxInputs = txCollateral
, _citxOutputs = InvalidTx
, _citxValidRange = txValidRange
, _citxData = txData <> otherDataHashes
Expand All @@ -130,12 +131,10 @@ mintingPolicies = Map.fromList . fmap withHash . Set.toList
withHash mp = let (MintingPolicyHash mph) = mintingPolicyHash mp
in (ScriptHash mph, getMintingPolicy mp)

validators :: Set TxIn -> (Map ScriptHash Script, Map DatumHash Datum, Redeemers)
validators txIns = foldMap (\(ix, txIn) -> maybe mempty (withHash ix) $ txInType txIn) $ zip [0..] (Set.toList txIns)
validators :: [TxIn] -> (Map ScriptHash Script, Map DatumHash Datum, Redeemers)
validators = foldMap (\(ix, txIn) -> maybe mempty (withHash ix) $ txInType txIn) . zip [0..] . sort
-- we sort the inputs to make sure that the indices match with redeemer pointers
where
-- TODO: the index of the txin is probably incorrect as we take it from the set.
-- To determine the proper index we have to convert the plutus's `TxIn` to cardano-api `TxIn` and
-- sort them by using the standard `Ord` instance.
withHash ix (ConsumeScriptAddress val red dat) =
let (ValidatorHash vh) = validatorHash val
in ( Map.singleton (ScriptHash vh) (getValidator val)
Expand Down
2 changes: 1 addition & 1 deletion plutus-contract/src/Plutus/Contract/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ assertAccumState contract inst p nm = TracePredicate $
let result = p w
unless result $ do
tell @(Doc Void) $ vsep
[ "Accumulated state of of" <+> pretty inst <> colon
[ "Accumulated state of" <+> pretty inst <> colon
, indent 2 (viaShow w)
, "Failed" <+> squotes (fromString nm)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import Data.Default
import Data.Either
import Data.Map qualified as Map
import Data.Maybe
import Data.Set qualified as Set
import Ledger.Params (EmulatorEra, Params)

import Ledger (unPaymentPrivateKey, unPaymentPubKeyHash)
Expand Down Expand Up @@ -298,12 +297,12 @@ showPretty cand = show . vcat $
| let tx0 = cand ^. to dsceTargetMattersProof . dsTx
tx1 = cand ^. to dsceValueStolenProof . dsTx
tx2 = cand ^. to dsceOriginalTransaction . dsTx
, ref <- Set.toList $ tx0 ^. inputs
<> tx1 ^. inputs
<> tx2 ^. inputs
<> tx0 ^. collateralInputs
<> tx1 ^. collateralInputs
<> tx2 ^. collateralInputs
, ref <- tx0 ^. inputs
<> tx1 ^. inputs
<> tx2 ^. inputs
<> tx0 ^. collateralInputs
<> tx1 ^. collateralInputs
<> tx2 ^. collateralInputs
]

isVulnerable :: DoubleSatisfactionCounterexample -> Bool
Expand Down Expand Up @@ -369,7 +368,7 @@ doubleSatisfactionCounterexamples dsc =
& dsTx .~ tx
, let valueStolen0 = dsc & l . outAddress .~ stealerAddr
& dsTx . outputs %~ (withDatumOut:)
& dsTx . inputs %~ (Set.insert newFakeTxIn)
& dsTx . inputs %~ (newFakeTxIn:)
& dsUtxoIndex %~
(\ (UtxoIndex m) -> UtxoIndex $ Map.insert newFakeTxOutRef
newFakeTxScriptOut m)
Expand Down
5 changes: 3 additions & 2 deletions plutus-contract/src/Plutus/Contract/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import Data.Map (Map)
import Data.Map qualified as Map
import Data.Maybe (mapMaybe)
import Data.OpenApi qualified as OpenApi
import Data.Semigroup qualified as Semigroup
import Data.Set qualified as Set
import Data.Typeable (Typeable)
import Data.Void (Void)
Expand Down Expand Up @@ -118,7 +119,7 @@ getUnspentOutput = do
let constraints = mustPayToPubKey ownPkh (Ada.lovelaceValueOf 1)
utx <- either (throwing _ConstraintResolutionContractError) pure (mkTx @Void mempty constraints)
tx <- Contract.adjustUnbalancedTx utx >>= Contract.balanceTx
case Set.lookupMin (getCardanoTxInputs tx) of
case fmap Semigroup.getMin $ foldMap (Just . Semigroup.Min) $ getCardanoTxInputs tx of
Just inp -> pure $ txInRef inp
Nothing -> throwing _OtherContractError "Balanced transaction has no inputs"

Expand Down Expand Up @@ -282,7 +283,7 @@ mkRedeemers :: P.Tx -> Either CardanoAPI.ToCardanoError [ExportTxRedeemer]
mkRedeemers tx = (++) <$> mkSpendingRedeemers tx <*> mkMintingRedeemers tx

mkSpendingRedeemers :: P.Tx -> Either CardanoAPI.ToCardanoError [ExportTxRedeemer]
mkSpendingRedeemers P.Tx{P.txInputs} = fmap join (traverse extract $ Set.toList txInputs) where
mkSpendingRedeemers P.Tx{P.txInputs} = fmap join (traverse extract txInputs) where
extract PV1.TxIn{PV1.txInType=Just (PV1.ConsumeScriptAddress _ redeemer _), PV1.txInRef} =
pure [SpendingRedeemer{redeemer, redeemerOutRef=txInRef}]
extract _ = pure []
Expand Down
15 changes: 8 additions & 7 deletions plutus-contract/src/Wallet/Emulator/Wallet.hs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import Data.Bifunctor (bimap, first, second)
import Data.Data
import Data.Default (Default (def))
import Data.Foldable (Foldable (fold), find, foldl')
import Data.List (sort)
import Data.Map qualified as Map
import Data.Maybe (catMaybes, fromMaybe, isNothing, listToMaybe)
import Data.OpenApi.Schema qualified as OpenApi
Expand Down Expand Up @@ -438,11 +439,11 @@ handleBalanceTx ::
handleBalanceTx utxo utx = do
Params { pProtocolParams } <- WAPI.getClientParams
let filteredUnbalancedTxTx = removeEmptyOutputs (view U.tx utx)
let txInputs = Set.toList $ Tx.txInputs filteredUnbalancedTxTx
let txInputs = Tx.txInputs filteredUnbalancedTxTx
ownPaymentPubKey <- gets ownPaymentPublicKey
let ownStakePubKey = Nothing
inputValues <- traverse lookupValue (Set.toList $ Tx.txInputs filteredUnbalancedTxTx)
collateral <- traverse lookupValue (Set.toList $ Tx.txCollateral filteredUnbalancedTxTx)
inputValues <- traverse lookupValue (Tx.txInputs filteredUnbalancedTxTx)
collateral <- traverse lookupValue (Tx.txCollateral filteredUnbalancedTxTx)
let fees = txFee filteredUnbalancedTxTx
left = txMint filteredUnbalancedTxTx <> fold inputValues
right = fees <> foldMap (view Tx.outValue) (filteredUnbalancedTxTx ^. Tx.outputs)
Expand Down Expand Up @@ -520,8 +521,8 @@ addCollateral
addCollateral mp vl tx = do
(spend, _) <- selectCoin (filter (Value.isAdaOnlyValue . snd) (second (view Ledger.ciTxOutValue) <$> Map.toList mp)) vl
let addTxCollateral =
let ins = Set.fromList (Tx.pubKeyTxIn . fst <$> spend)
in over Tx.collateralInputs (Set.union ins)
let ins = Tx.pubKeyTxIn . fst <$> spend
in over Tx.collateralInputs (sort . (++) ins)
pure $ tx & addTxCollateral

-- | @addInputs mp pk vl tx@ selects transaction outputs worth at least
Expand All @@ -541,8 +542,8 @@ addInputs mp pk sk vl tx = do
let

addTxIns =
let ins = Set.fromList (Tx.pubKeyTxIn . fst <$> spend)
in over Tx.inputs (Set.union ins)
let ins = Tx.pubKeyTxIn . fst <$> spend
in over Tx.inputs (sort . (++) ins)

addTxOut =
if Value.isZero change
Expand Down
2 changes: 1 addition & 1 deletion plutus-contract/src/Wallet/Graph.hs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ txnFlows keys bc = catMaybes (utxoLinks ++ foldMap extract bc')
extract :: (UtxoLocation, OnChainTx) -> [Maybe FlowLink]
extract (loc, tx) =
let targetRef = mkRef $ eitherTx getCardanoTxId getCardanoTxId tx in
fmap (flow (Just loc) targetRef . txInRef) (Set.toList $ consumableInputs tx)
fmap (flow (Just loc) targetRef . txInRef) (consumableInputs tx)
-- make a flow for a TxOutRef

flow :: Maybe UtxoLocation -> TxRef -> TxOutRef -> Maybe FlowLink
Expand Down
3 changes: 1 addition & 2 deletions plutus-contract/src/Wallet/Rollup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import Control.Monad.State (StateT, evalStateT, runState)
import Data.List (groupBy)
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Set qualified as Set
import Ledger (Block, Blockchain, OnChainTx (..), TxIn (TxIn), TxOut (TxOut), ValidationPhase (..), Value,
consumableInputs, eitherTx, outValue, txInRef, txOutRefId, txOutRefIdx, txOutValue)
import Ledger.Tx qualified as Tx
Expand Down Expand Up @@ -48,7 +47,7 @@ annotateTransaction sequenceId tx = do
in case Map.lookup key cPreviousOutputs of
Just txOut -> pure $ DereferencedInput txIn txOut
Nothing -> pure $ InputNotFound key)
(Set.toList $ consumableInputs tx)
(consumableInputs tx)
let txId = eitherTx Tx.getCardanoTxId Tx.getCardanoTxId tx
txOuts = eitherTx (const []) Tx.getCardanoTxOutputs tx
newOutputs =
Expand Down
3 changes: 1 addition & 2 deletions plutus-contract/test/Spec/Emulator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import Data.ByteString.Lazy qualified as BSL
import Data.ByteString.Lazy.Char8 (pack)
import Data.Default (Default (def))
import Data.Foldable (fold)
import Data.Set qualified as Set
import Hedgehog (Property, forAll, property)
import Hedgehog qualified
import Hedgehog.Gen qualified as Gen
Expand Down Expand Up @@ -222,7 +221,7 @@ invalidScript = property $ do
let totalVal = txOutValue (fst outToSpend)

-- try and spend the script output
invalidTxn <- forAll $ Gen.genValidTransactionSpending (Set.fromList [scriptTxIn (snd outToSpend) failValidator unitRedeemer unitDatum]) totalVal
invalidTxn <- forAll $ Gen.genValidTransactionSpending [scriptTxIn (snd outToSpend) failValidator unitRedeemer unitDatum] totalVal
Hedgehog.annotateShow invalidTxn

let options = defaultCheckOptions & emulatorConfig . Trace.initialChainState .~ Right m
Expand Down
Loading

0 comments on commit 98ad189

Please sign in to comment.