Skip to content

Commit 4759b37

Browse files
committed
Use Exp.TxOut directly in Compatible/TxOut; simplify Byron output types
1 parent f017b71 commit 4759b37

6 files changed

Lines changed: 138 additions & 94 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
project: cardano-cli
2+
3+
pr: 1392
4+
5+
kind:
6+
- refactoring
7+
8+
description: |
9+
Build Exp.TxOut directly via ledger constructors in Compatible/Transaction/TxOut,
10+
eliminating the TxOut CtxTx era intermediate. Simplify Byron output types to
11+
(Address ByronAddr, L.Coin) throughout the Byron command path.

cardano-cli/src/Cardano/CLI/Byron/Command.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ where
1313

1414
import Cardano.Api hiding (GenesisParameters)
1515
import Cardano.Api.Byron qualified as Byron
16+
import Cardano.Api.Ledger qualified as L
1617

1718
import Cardano.CLI.Byron.Genesis
1819
import Cardano.CLI.Byron.Key
@@ -67,7 +68,7 @@ data ByronCommand
6768
-- ^ Signing key of genesis UTxO owner.
6869
(Address ByronAddr)
6970
-- ^ Genesis UTxO address.
70-
[TxOut CtxTx ByronEra]
71+
[(Address ByronAddr, L.Coin)]
7172
-- ^ Tx output.
7273
| SpendUTxO
7374
NetworkId
@@ -78,7 +79,7 @@ data ByronCommand
7879
-- ^ Signing key of Tx underwriter.
7980
[TxIn]
8081
-- ^ Inputs available for spending to the Tx underwriter's key.
81-
[TxOut CtxTx ByronEra]
82+
[(Address ByronAddr, L.Coin)]
8283
-- ^ Genesis UTxO output Address.
8384
| GetTxId (TxFile In)
8485
| --- Misc Commands ---

cardano-cli/src/Cardano/CLI/Byron/Parser.hs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -282,33 +282,25 @@ parseTxIdAtto = (<?> "Transaction ID (hexadecimal)") $ do
282282
parseTxIxAtto :: Atto.Parser TxIx
283283
parseTxIxAtto = toEnum <$> Atto.decimal
284284

285-
parseTxOut :: Parser (TxOut CtxTx ByronEra)
285+
parseTxOut :: Parser (Address ByronAddr, L.Coin)
286286
parseTxOut =
287287
Opt.option
288-
( ( \(addr, lovelace) ->
289-
TxOut
290-
(pAddressInEra addr)
291-
(pLovelaceTxOut lovelace)
292-
TxOutDatumNone
293-
ReferenceScriptNone
294-
)
295-
<$> auto
296-
)
288+
((\(addr, lovelace) -> (parseByronAddr addr, pLovelaceCoin lovelace)) <$> auto)
297289
$ long "txout"
298290
<> metavar "'(\"ADDR\", LOVELACE)'"
299291
<> help "Specify a transaction output, as a pair of an address and lovelace."
300292
where
301-
pAddressInEra :: Text -> AddressInEra ByronEra
302-
pAddressInEra t =
293+
parseByronAddr :: Text -> Address ByronAddr
294+
parseByronAddr t =
303295
case Byron.decodeAddressBase58 t of
304296
Left err -> error $ "Bad Base58 address: " <> show err
305-
Right byronAddress -> AddressInEra ByronAddressInAnyEra $ ByronAddress byronAddress
297+
Right byronAddress -> ByronAddress byronAddress
306298

307-
pLovelaceTxOut :: Word64 -> TxOutValue ByronEra
308-
pLovelaceTxOut l =
299+
pLovelaceCoin :: Word64 -> L.Coin
300+
pLovelaceCoin l =
309301
if l > (maxBound :: Word64)
310302
then error $ show l <> " lovelace exceeds the Word64 upper bound"
311-
else TxOutValueByron $ L.Coin $ toInteger l
303+
else L.Coin $ toInteger l
312304

313305
readerFromAttoParser :: Atto.Parser a -> Opt.ReadM a
314306
readerFromAttoParser p =

cardano-cli/src/Cardano/CLI/Byron/Run.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Cardano.Api.Byron
1717
, VerificationKey (ByronVerificationKey)
1818
)
1919
import Cardano.Api.Byron qualified as Byron
20+
import Cardano.Api.Ledger qualified as L
2021

2122
import Cardano.CLI.Byron.Command
2223
import Cardano.CLI.Byron.Delegation
@@ -176,7 +177,7 @@ runSpendGenesisUTxO
176177
-> NewTxFile
177178
-> SigningKeyFile In
178179
-> Address ByronAddr
179-
-> [TxOut CtxTx ByronEra]
180+
-> [(Address ByronAddr, L.Coin)]
180181
-> CIO e ()
181182
runSpendGenesisUTxO genesisFile nw bKeyFormat (NewTxFile ctTx) ctKey genRichAddr outs = do
182183
genesis <- fromExceptTCli $ readGenesis genesisFile nw
@@ -195,7 +196,7 @@ runSpendUTxO
195196
-> NewTxFile
196197
-> SigningKeyFile In
197198
-> [TxIn]
198-
-> [TxOut CtxTx ByronEra]
199+
-> [(Address ByronAddr, L.Coin)]
199200
-> CIO e ()
200201
runSpendUTxO nw bKeyFormat (NewTxFile ctTx) ctKey ins outs = do
201202
sk <- fromExceptTCli $ readByronSigningKey bKeyFormat ctKey

cardano-cli/src/Cardano/CLI/Byron/Tx.hs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,20 @@ txSpendGenesisUTxOByronPBFT
144144
-> NetworkId
145145
-> Byron.SomeByronSigningKey
146146
-> Address ByronAddr
147-
-> [TxOut CtxTx ByronEra]
147+
-> [(Address ByronAddr, L.Coin)]
148148
-> Byron.ATxAux ByteString
149-
txSpendGenesisUTxOByronPBFT gc nId sk (ByronAddress bAddr) outs =
149+
txSpendGenesisUTxOByronPBFT gc nId sk (ByronAddress bAddr) outs' =
150150
let txins = [(Byron.fromByronTxIn txIn, BuildTxWith (KeyWitness KeyWitnessForSpending))]
151-
in case makeByronTransactionBody txins outs of
151+
outs =
152+
[ TxOut
153+
(AddressInEra ByronAddressInAnyEra addr)
154+
(TxOutValueByron coin)
155+
TxOutDatumNone
156+
ReferenceScriptNone
157+
| (addr, coin) <- outs'
158+
]
159+
in -- TODO: switch to the ledger's TxOut type for Byron once makeByronTransactionBody is updated
160+
case makeByronTransactionBody txins outs of
152161
Left err -> error $ "Error occurred while creating a Byron genesis based UTxO transaction: " <> show err
153162
Right txBody ->
154163
let bWit = fromByronWitness sk nId txBody
@@ -165,11 +174,19 @@ txSpendUTxOByronPBFT
165174
:: NetworkId
166175
-> Byron.SomeByronSigningKey
167176
-> [TxIn]
168-
-> [TxOut CtxTx ByronEra]
177+
-> [(Address ByronAddr, L.Coin)]
169178
-> Byron.ATxAux ByteString
170-
txSpendUTxOByronPBFT nId sk txIns outs = do
179+
txSpendUTxOByronPBFT nId sk txIns outs' = do
171180
let apiTxIns = [(txIn, BuildTxWith (KeyWitness KeyWitnessForSpending)) | txIn <- txIns]
172-
181+
outs =
182+
[ TxOut
183+
(AddressInEra ByronAddressInAnyEra addr)
184+
(TxOutValueByron coin)
185+
TxOutDatumNone
186+
ReferenceScriptNone
187+
| (addr, coin) <- outs'
188+
]
189+
-- TODO: switch to the ledger's TxOut type for Byron once makeByronTransactionBody is updated
173190
case makeByronTransactionBody apiTxIns outs of
174191
Left err -> error $ "Error occurred while creating a Byron genesis based UTxO transaction: " <> show err
175192
Right txBody ->

cardano-cli/src/Cardano/CLI/Compatible/Transaction/TxOut.hs

Lines changed: 90 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ import Cardano.CLI.EraBased.Script.Read.Common
1818
import Cardano.CLI.Orphan ()
1919
import Cardano.CLI.Read
2020
import Cardano.CLI.Type.Common
21+
import Cardano.Ledger.Api.Tx qualified as L
2122
import Cardano.Ledger.Hashes (DataHash)
22-
import Cardano.Ledger.Plutus.Data qualified as L
2323

2424
import Data.Map.Strict (Map)
2525
import Data.Map.Strict qualified as Map
26+
import Lens.Micro
2627

2728
toTxOutInAnyEra
2829
:: ShelleyBasedEra era
@@ -32,51 +33,101 @@ toTxOutInAnyEra era (TxOutAnyEra addr' val' mDatumHash refScriptFp) = do
3233
let addr = anyAddressInShelleyBasedEra era addr'
3334
mkTxOut era addr val' mDatumHash refScriptFp
3435

35-
-- | Build an output for a transaction body. Produces the experimental
36-
-- 'Exp.TxOut' plus any supplemental datum bodies that the caller-supplied
37-
-- datum carries. The legacy 'TxOut CtxTx era' bundled supplemental datums
38-
-- inside outputs; 'Exp.TxOut' only carries the datum hash, so callers thread
39-
-- the full datum bodies in separately (e.g. via 'createCompatibleTx').
40-
--
41-
-- The legacy 'TxOut CtxTx era' is used internally as a stepping stone to
42-
-- reuse the api's 'toShelleyTxOutAny' field-level conversion logic; it is
43-
-- not exposed.
4436
mkTxOut
4537
:: ShelleyBasedEra era
4638
-> AddressInEra era
4739
-> Value
4840
-> TxOutDatumAnyEra
4941
-> ReferenceScriptAnyEra
5042
-> CIO e (Exp.TxOut (ShelleyLedgerEra era), Map DataHash (L.Data (ShelleyLedgerEra era)))
51-
mkTxOut sbe addr val' mDatumHash refScriptFp = do
52-
let era = toCardanoEra sbe
53-
val <- toTxOutValueInShelleyBasedEra sbe val'
54-
55-
datum <-
56-
inEonForEra
57-
(pure TxOutDatumNone)
58-
(`toTxAlonzoDatum` mDatumHash)
59-
era
60-
61-
refScript <-
62-
inEonForEra
63-
(pure ReferenceScriptNone)
64-
(`getReferenceScript` refScriptFp)
65-
era
66-
67-
let legacyTxOut = TxOut addr val datum refScript
68-
pure $
69-
shelleyBasedEraConstraints sbe $
70-
(Exp.TxOut (toShelleyTxOutAny sbe legacyTxOut), supplementalsOf datum)
71-
where
72-
supplementalsOf
73-
:: L.Era (ShelleyLedgerEra era)
74-
=> TxOutDatum CtxTx era
75-
-> Map DataHash (L.Data (ShelleyLedgerEra era))
76-
supplementalsOf (TxOutSupplementalDatum _ h) =
77-
let ld = toAlonzoData h
78-
in Map.singleton (L.hashData ld) ld
79-
supplementalsOf _ = mempty
43+
mkTxOut sbe addr val' mDatumAnyEra refScriptFp = do
44+
txVal <- toTxOutValueInShelleyBasedEra sbe val'
45+
let ledgerAddr = toShelleyAddr addr
46+
shelleyBasedEraConstraints sbe $
47+
case txVal of
48+
TxOutValueShelleyBased _ ledgerVal ->
49+
case sbe of
50+
ShelleyBasedEraShelley -> pure (Exp.TxOut (L.mkBasicTxOut ledgerAddr ledgerVal), mempty)
51+
ShelleyBasedEraAllegra -> pure (Exp.TxOut (L.mkBasicTxOut ledgerAddr ledgerVal), mempty)
52+
ShelleyBasedEraMary -> pure (Exp.TxOut (L.mkBasicTxOut ledgerAddr ledgerVal), mempty)
53+
ShelleyBasedEraAlonzo -> do
54+
(mDH, suppl) <- alonzoDatumFields mDatumAnyEra
55+
pure
56+
( Exp.TxOut (L.mkBasicTxOut ledgerAddr ledgerVal & L.dataHashTxOutL .~ mDH)
57+
, suppl
58+
)
59+
ShelleyBasedEraBabbage -> do
60+
(dat, suppl) <- babbageDatumFields mDatumAnyEra
61+
refScript <- readRefScript sbe refScriptFp
62+
pure
63+
( Exp.TxOut
64+
( L.mkBasicTxOut ledgerAddr ledgerVal
65+
& L.datumTxOutL .~ dat
66+
& L.referenceScriptTxOutL .~ refScript
67+
)
68+
, suppl
69+
)
70+
ShelleyBasedEraConway -> do
71+
(dat, suppl) <- babbageDatumFields mDatumAnyEra
72+
refScript <- readRefScript sbe refScriptFp
73+
pure
74+
( Exp.TxOut
75+
( L.mkBasicTxOut ledgerAddr ledgerVal
76+
& L.datumTxOutL .~ dat
77+
& L.referenceScriptTxOutL .~ refScript
78+
)
79+
, suppl
80+
)
81+
82+
alonzoDatumFields
83+
:: L.Era ledgerera
84+
=> TxOutDatumAnyEra
85+
-> CIO e (L.StrictMaybe DataHash, Map DataHash (L.Data ledgerera))
86+
alonzoDatumFields = \case
87+
TxOutDatumByNone ->
88+
pure (L.SNothing, mempty)
89+
TxOutDatumByHashOnly h ->
90+
pure (L.SJust (unScriptDataHash h), mempty)
91+
TxOutDatumByHashOf sDataOrFile -> do
92+
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
93+
pure (L.SJust (unScriptDataHash (hashScriptDataBytes sData)), mempty)
94+
TxOutDatumByValue sDataOrFile -> do
95+
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
96+
let ld = toAlonzoData sData
97+
dh = L.hashData ld
98+
pure (L.SJust dh, Map.singleton dh ld)
99+
TxOutInlineDatumByValue _ ->
100+
throwCliError $ TxCmdTxFeatureMismatch (AnyCardanoEra AlonzoEra) TxFeatureInlineDatums
101+
102+
babbageDatumFields
103+
:: L.Era ledgerera
104+
=> TxOutDatumAnyEra
105+
-> CIO e (L.Datum ledgerera, Map DataHash (L.Data ledgerera))
106+
babbageDatumFields = \case
107+
TxOutDatumByNone ->
108+
pure (L.NoDatum, mempty)
109+
TxOutDatumByHashOnly h ->
110+
pure (L.DatumHash (unScriptDataHash h), mempty)
111+
TxOutDatumByHashOf sDataOrFile -> do
112+
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
113+
pure (L.DatumHash (unScriptDataHash (hashScriptDataBytes sData)), mempty)
114+
TxOutDatumByValue sDataOrFile -> do
115+
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
116+
let dh = unScriptDataHash (hashScriptDataBytes sData)
117+
pure (L.DatumHash dh, Map.singleton dh (toAlonzoData sData))
118+
TxOutInlineDatumByValue sDataOrFile -> do
119+
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
120+
pure (scriptDataToInlineDatum sData, mempty)
121+
122+
readRefScript
123+
:: ShelleyBasedEra era
124+
-> ReferenceScriptAnyEra
125+
-> CIO e (L.StrictMaybe (L.Script (ShelleyLedgerEra era)))
126+
readRefScript sbe = \case
127+
ReferenceScriptAnyEraNone -> pure L.SNothing
128+
ReferenceScriptAnyEra fp -> do
129+
script <- readFileScriptInAnyLang fp
130+
pure $ maybe L.SNothing (L.SJust . toShelleyScript) (toScriptInEra sbe script)
80131

81132
toTxOutValueInShelleyBasedEra
82133
:: ShelleyBasedEra era
@@ -91,35 +142,6 @@ toTxOutValueInShelleyBasedEra sbe val =
91142
(\w -> return (TxOutValueShelleyBased sbe (toLedgerValue w val)))
92143
sbe
93144

94-
toTxAlonzoDatum
95-
:: ()
96-
=> AlonzoEraOnwards era
97-
-> TxOutDatumAnyEra
98-
-> CIO e (TxOutDatum CtxTx era)
99-
toTxAlonzoDatum supp cliDatum =
100-
case cliDatum of
101-
TxOutDatumByNone -> pure TxOutDatumNone
102-
TxOutDatumByHashOnly h -> pure (TxOutDatumHash supp h)
103-
TxOutDatumByHashOf sDataOrFile -> do
104-
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
105-
pure (TxOutDatumHash supp $ hashScriptDataBytes sData)
106-
TxOutDatumByValue sDataOrFile -> do
107-
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
108-
pure (TxOutSupplementalDatum supp sData)
109-
TxOutInlineDatumByValue sDataOrFile -> do
110-
let cEra = toCardanoEra supp
111-
forEraInEon cEra (txFeatureMismatch cEra TxFeatureInlineDatums) $ \babbageOnwards -> do
112-
sData <- fromExceptTCli $ readScriptDataOrFile sDataOrFile
113-
pure $ TxOutDatumInline babbageOnwards sData
114-
115-
getReferenceScript
116-
:: BabbageEraOnwards era
117-
-> ReferenceScriptAnyEra
118-
-> CIO e (ReferenceScript era)
119-
getReferenceScript w = \case
120-
ReferenceScriptAnyEraNone -> return ReferenceScriptNone
121-
ReferenceScriptAnyEra fp -> ReferenceScript w <$> readFileScriptInAnyLang fp
122-
123145
-- | An enumeration of era-dependent features where we have to check that it
124146
-- is permissible to use this feature in this era.
125147
data TxFeature

0 commit comments

Comments
 (0)