Skip to content

Commit

Permalink
Start removing SerializedTxOutRef from commit validator's datum
Browse files Browse the repository at this point in the history
  Not needed, but was handy for observing commit. Removing it makes on-chain validations easier / less error prone.
  • Loading branch information
KtorZ authored and ch1bo committed Jan 26, 2022
1 parent 52a6d8a commit 1219b8d
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 25 deletions.
40 changes: 24 additions & 16 deletions hydra-node/src/Hydra/Chain/Direct/Tx.hs
Expand Up @@ -52,6 +52,7 @@ import Hydra.Ledger.Cardano (
PaymentKey,
Utxo,
VerificationKey (PaymentVerificationKey),
filterTxIn,
fromLedgerTx,
fromPlutusScript,
getDatum,
Expand Down Expand Up @@ -220,11 +221,8 @@ mkCommitDatum (partyFromVerKey . vkey -> party) headValidatorHash utxo =
serializedUtxo = case utxo of
Nothing ->
Nothing
Just (i, o) ->
Just
( Commit.SerializedTxOutRef (toBuiltin $ serialize' $ Api.toLedgerTxIn i)
, Commit.SerializedTxOut (toBuiltin $ serialize' $ Api.toLedgerTxOut o)
)
Just (_i, o) ->
Just $ Commit.SerializedTxOut (toBuiltin $ serialize' $ Api.toLedgerTxOut o)

-- | Create a transaction collecting all "committed" utxo and opening a Head,
-- i.e. driving the Head script state.
Expand Down Expand Up @@ -458,15 +456,28 @@ convertParty :: OnChain.Party -> Party
convertParty = Party . partyToVerKey

-- | Identify a commit tx by looking for an output which pays to v_commit.
--
-- To reconstruct a commit from a commit transaction we need to:
--
-- - Find out which 'initials' is being committed
-- - Find the redeemer corresponding to that 'initial' which contain the
-- output-reference of the commit
-- - Find the outputs which pays to the commit validator
-- - Extract the datum of that output, which contains the output of the commit
-- - Reconstruct the committed UTXO from both values (output ref and output).
observeCommitTx ::
Api.NetworkId ->
-- TODO: This type may be too large for this function, we only probably need
-- just the TxIn.
[TxIn StandardCrypto] ->
ValidatedTx Era ->
Maybe (OnChainTx CardanoTx, (TxIn StandardCrypto, TxOut Era, Data Era))
observeCommitTx networkId (Api.getTxBody . fromLedgerTx -> txBody) = do
observeCommitTx networkId initials (Api.getTxBody . fromLedgerTx -> txBody) = do
let ins = filterTxIn (`elem` initials) txBody
(commitIn, commitOut) <- Api.findTxOutByAddress commitAddress txBody
dat <- getDatum commitOut
(party, _, committedUtxo) <- fromData @(DatumType Commit.Commit) $ toPlutusData dat
convertedUtxo <- convertUtxo committedUtxo
(party, _, serializedTxOut) <- fromData @(DatumType Commit.Commit) $ toPlutusData dat
convertedTxOut <- convertTxOut serializedTxOut
let onChainTx = OnCommitTx (convertParty party) convertedUtxo
pure
( onChainTx
Expand All @@ -477,16 +488,13 @@ observeCommitTx networkId (Api.getTxBody . fromLedgerTx -> txBody) = do
)
)
where
convertUtxo :: Maybe (Commit.SerializedTxOutRef, Commit.SerializedTxOut) -> Maybe Utxo
convertUtxo = \case
convertTxOut :: Maybe Commit.SerializedTxOut -> Maybe (TxOut Era)
convertTxOut = \case
Nothing -> Just mempty
Just (Commit.SerializedTxOutRef inBytes, Commit.SerializedTxOut outBytes) ->
Just (Commit.SerializedTxOut outBytes) ->
-- XXX(SN): these errors might be more severe and we could throw an
-- exception here?
eitherToMaybe $ do
txIn <- Api.fromLedgerTxIn <$> decodeFull' (fromBuiltin inBytes)
txOut <- Api.fromLedgerTxOut <$> decodeFull' (fromBuiltin outBytes)
pure $ Api.singletonUtxo (txIn, txOut)
eitherToMaybe $ decodeFull' (fromBuiltin outBytes)

commitAddress = mkScriptAddress @Api.PlutusScriptV1 networkId commitScript

Expand All @@ -501,7 +509,7 @@ observeCommit ::
Maybe (OnChainTx CardanoTx, OnChainHeadState)
observeCommit networkId tx = \case
Initial{threadOutput, initials, commits} -> do
(onChainTx, commitTriple) <- observeCommitTx networkId tx
(onChainTx, commitTriple) <- observeCommitTx networkId initials tx
-- NOTE(SN): A commit tx has been observed and thus we can remove all it's
-- inputs from our tracked initials
let commitIns = inputs $ body tx
Expand Down
5 changes: 5 additions & 0 deletions hydra-node/src/Hydra/Ledger/Cardano.hs
Expand Up @@ -401,6 +401,11 @@ mkSimpleCardanoTx (txin, TxOut owner txOutValueIn datum) (recipient, valueOut) s
mkTxIn :: TxBody era -> Word -> TxIn
mkTxIn txBody index = TxIn (getTxId txBody) (TxIx index)

-- | Filter txins of a transaction given the predicate.
filterTxIn :: (TxIn -> Bool) -> TxBody Era -> [TxIn]
filterTxIn fn (TxBody body) =
filter fn (fst <$> txIns body)

-- ** TxOut

-- XXX(SN): replace with Cardano.Api.TxBody.lovelaceToTxOutValue when available
Expand Down
5 changes: 1 addition & 4 deletions hydra-plutus/src/Hydra/Contract/Commit.hs
Expand Up @@ -19,9 +19,6 @@ import PlutusTx.IsData.Class (FromData (fromBuiltinData), ToData (..))

data Commit

newtype SerializedTxOutRef = SerializedTxOutRef BuiltinByteString
PlutusTx.unstableMakeIsData ''SerializedTxOutRef

newtype SerializedTxOut = SerializedTxOut BuiltinByteString
PlutusTx.unstableMakeIsData ''SerializedTxOut

Expand All @@ -34,7 +31,7 @@ instance Eq SerializedTxOut where
-- Ideally, since the TxOutRef is already present in the redeemer for the
-- initial validator, the off-chain code could get it from there.
instance Scripts.ValidatorTypes Commit where
type DatumType Commit = (Party, ValidatorHash, Maybe (SerializedTxOutRef, SerializedTxOut))
type DatumType Commit = (Party, ValidatorHash, Maybe SerializedTxOut)
type RedeemerType Commit = ()

validator :: DatumType Commit -> RedeemerType Commit -> ScriptContext -> Bool
Expand Down
2 changes: 1 addition & 1 deletion hydra-plutus/src/Hydra/Contract/Head.hs
Expand Up @@ -132,7 +132,7 @@ checkCollectCom commitAddress (_, parties) context@ScriptContext{scriptContextTx
lookupCommit h = do
d <- getDatum <$> findDatum h txInfo
case fromBuiltinData @(DatumType Commit) d of
Just (_p, _, Just (_, o)) ->
Just (_p, _, Just o) ->
Just o
Just (_p, _, Nothing) ->
Nothing
Expand Down
8 changes: 4 additions & 4 deletions hydra-plutus/src/Hydra/Contract/Initial.hs
Expand Up @@ -9,7 +9,7 @@ module Hydra.Contract.Initial where
import Ledger hiding (validatorHash)
import PlutusTx.Prelude

import Hydra.Contract.Commit (SerializedTxOut (SerializedTxOut), SerializedTxOutRef)
import Hydra.Contract.Commit (SerializedTxOut (..))
import qualified Hydra.Contract.Commit as Commit
import Hydra.Contract.Encoding (encodeTxOut)
import Hydra.Data.Party (Party)
Expand Down Expand Up @@ -70,10 +70,10 @@ checkCommit commitValidator committedRef context@ScriptContext{scriptContextTxIn
case getDatum <$> findDatum dh txInfo of
Nothing -> traceError "Invalid datum hash with no datum"
(Just da) ->
case fromBuiltinData @(Party, ValidatorHash, Maybe (SerializedTxOutRef, SerializedTxOut)) da of
case fromBuiltinData @(Party, ValidatorHash, Maybe SerializedTxOut) da of
Just (_party, _headScriptHash, Nothing) ->
traceIfFalse "committed UTXO is not in output datum" $ isNothing committedRef
Just (_party, _headScriptHash, Just (_serialisedTxOutRef, serialisedTxOut)) ->
Just (_party, _headScriptHash, Just serialisedTxOut) ->
case txInInfoResolved <$> committedTxOut of
Nothing -> traceError "unexpected UTXO in output datum"
Just txOut ->
Expand All @@ -86,7 +86,7 @@ checkCommit commitValidator committedRef context@ScriptContext{scriptContextTxIn
maybe mempty (txOutValue . txInInfoResolved) $ findOwnInput context

committedValue =
maybe mempty (txOutValue . txInInfoResolved) $ committedTxOut
maybe mempty (txOutValue . txInInfoResolved) committedTxOut

committedTxOut = do
ref <- committedRef
Expand Down

0 comments on commit 1219b8d

Please sign in to comment.