Skip to content

Commit 90fa0f2

Browse files
committed
Add TxLevel module
1 parent 1bd37de commit 90fa0f2

File tree

4 files changed

+155
-108
lines changed

4 files changed

+155
-108
lines changed

libs/cardano-ledger-core/cardano-ledger-core.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ library
7676
Cardano.Ledger.Core.PParams
7777
Cardano.Ledger.Core.Translation
7878
Cardano.Ledger.Core.TxCert
79+
Cardano.Ledger.Core.TxLevel
7980
Cardano.Ledger.Keys.Internal
8081
Cardano.Ledger.State.Account
8182
Cardano.Ledger.State.CertState

libs/cardano-ledger-core/src/Cardano/Ledger/Core.hs

Lines changed: 57 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,7 @@
2727
-- > import qualified Cardano.Ledger.Core as Core
2828
module Cardano.Ledger.Core (
2929
-- * Transaction types
30-
TxType (..),
31-
STxType (..),
32-
withTxType,
33-
applyTxType,
34-
applyFullTxType,
30+
module Cardano.Ledger.Core.TxLevel,
3531

3632
-- * Era-changing types
3733
EraTx (..),
@@ -77,6 +73,7 @@ module Cardano.Ledger.Core (
7773
module Cardano.Ledger.Core.Translation,
7874
) where
7975

76+
import Cardano.Ledger.Core.TxLevel
8077
import qualified Cardano.Crypto.Hash as Hash
8178
import Cardano.Ledger.Address (
8279
Addr (..),
@@ -142,72 +139,39 @@ import GHC.Stack (HasCallStack)
142139
import Lens.Micro
143140
import NoThunks.Class (NoThunks)
144141

145-
type data TxType = FullTx | SubTx
146-
147-
withTxType ::
148-
forall f t a era. Typeable t => f t era -> (f FullTx era -> a) -> (f SubTx era -> a) -> a
149-
withTxType anyTxType withFullTxType withSubTxType =
150-
case eqT @t @FullTx of
151-
Just Refl -> withFullTxType anyTxType
152-
Nothing -> case eqT @t @SubTx of
153-
Just Refl -> withSubTxType anyTxType
154-
Nothing -> error $ "Impossible: Unrecognized TxType: " <> show (typeRep (Proxy @t))
155-
156-
applyTxType ::
157-
forall f t m era. (Typeable t, HasCallStack) => m (f FullTx era) -> m (f SubTx era) -> m (f t era)
158-
applyTxType decFullTx decSubTx =
159-
case eqT @t @FullTx of
160-
Just Refl -> decFullTx
161-
Nothing -> case eqT @t @SubTx of
162-
Just Refl -> decSubTx
163-
Nothing -> error $ "Impossible: Unrecognized TxType: " <> show (typeRep (Proxy @t))
164-
165-
-- | Same as `applyTxType`, but will `fail` if `SubTx` transaction type is requested.
166-
applyFullTxType ::
167-
forall f t m era. (Typeable f, Typeable t, MonadFail m) => m (f FullTx era) -> m (f t era)
168-
applyFullTxType decFullTx =
169-
applyTxType decFullTx $
170-
fail $
171-
"SubTx type is not supported for " <> show (typeRep (Proxy @f))
172-
173-
data STxType t where
174-
SFullTx :: STxType FullTx
175-
SSubTx :: STxType SubTx
176-
177142
-- | A transaction.
178143
class
179144
( EraTxBody era
180145
, EraTxWits era
181146
, EraTxAuxData era
182147
, EraPParams era
183-
, forall t. Typeable t => NoThunks (Tx t era)
184-
, forall t. Typeable t => DecCBOR (Annotator (Tx t era))
185-
, forall t. Typeable t => ToCBOR (Tx t era)
186-
, forall t. EncCBOR (Tx t era)
187-
, forall t. NFData (Tx t era)
188-
, forall t. Show (Tx t era)
189-
, forall t. Eq (Tx t era)
148+
, HasEraTxLevel Tx era
149+
, forall l. Typeable l => NoThunks (Tx l era)
150+
, forall l. Typeable l => DecCBOR (Annotator (Tx l era))
151+
, forall l. Typeable l => ToCBOR (Tx l era)
152+
, forall l. EncCBOR (Tx l era)
153+
, forall l. NFData (Tx l era)
154+
, forall l. Show (Tx l era)
155+
, forall l. Eq (Tx l era)
190156
) =>
191157
EraTx era
192158
where
193-
data Tx (t :: TxType) era
194-
195-
txType :: Tx t era -> KnownTxType t era
159+
data Tx (l :: TxLevel) era
196160

197-
mkBasicTx :: Typeable t => TxBody t era -> Tx t era
161+
mkBasicTx :: TxBody l era -> Tx l era
198162

199-
bodyTxL :: Lens' (Tx t era) (TxBody t era)
163+
bodyTxL :: Lens' (Tx l era) (TxBody l era)
200164

201-
witsTxL :: Lens' (Tx t era) (TxWits era)
165+
witsTxL :: Lens' (Tx l era) (TxWits era)
202166

203-
auxDataTxL :: Lens' (Tx t era) (StrictMaybe (TxAuxData era))
167+
auxDataTxL :: Lens' (Tx l era) (StrictMaybe (TxAuxData era))
204168

205169
-- | For fee calculation and estimations of impact on block space
206-
sizeTxF :: HasCallStack => SimpleGetter (Tx t era) Word32
170+
sizeTxF :: HasCallStack => SimpleGetter (Tx l era) Word32
207171

208172
-- | For fee calculation and estimations of impact on block space
209173
-- To replace `sizeTxF` after it has been proved equivalent to it .
210-
sizeTxForFeeCalculation :: (HasCallStack, SafeToHash (TxWits era)) => Tx t era -> Word32
174+
sizeTxForFeeCalculation :: (HasCallStack, SafeToHash (TxWits era)) => Tx l era -> Word32
211175
sizeTxForFeeCalculation tx =
212176
errorFail $
213177
integralToBounded @Int @Word32 $
@@ -217,12 +181,12 @@ class
217181
+ 1 -- account for the top-level CBOR encoding tag
218182

219183
-- | Using information from the transaction validate the supplied native script.
220-
validateNativeScript :: Tx t era -> NativeScript era -> Bool
184+
validateNativeScript :: Tx l era -> NativeScript era -> Bool
221185

222186
-- | Minimum fee calculation excluding witnesses
223187
getMinFeeTx ::
224188
PParams era ->
225-
Tx t era ->
189+
Tx l era ->
226190
-- | Size in bytes of reference scripts present in this transaction
227191
Int ->
228192
Coin
@@ -231,47 +195,45 @@ class
231195
( EraTxOut era
232196
, EraTxCert era
233197
, EraPParams era
234-
, forall t. HashAnnotated (TxBody t era) EraIndependentTxBody
235-
, forall t. EncCBOR (TxBody t era)
236-
, forall t. Typeable t => DecCBOR (Annotator (TxBody t era))
237-
, forall t. Typeable t => ToCBOR (TxBody t era)
238-
, forall t. Typeable t => NoThunks (TxBody t era)
239-
, forall t. NFData (TxBody t era)
240-
, forall t. Show (TxBody t era)
241-
, forall t. Eq (TxBody t era)
242-
, forall t. EqRaw (TxBody t era)
198+
, HasEraTxLevel TxBody era
199+
, forall l. HashAnnotated (TxBody l era) EraIndependentTxBody
200+
, forall l. EncCBOR (TxBody l era)
201+
, forall l. Typeable l => DecCBOR (Annotator (TxBody l era))
202+
, forall l. Typeable l => ToCBOR (TxBody l era)
203+
, forall l. Typeable l => NoThunks (TxBody l era)
204+
, forall l. NFData (TxBody l era)
205+
, forall l. Show (TxBody l era)
206+
, forall l. Eq (TxBody l era)
207+
, forall l. EqRaw (TxBody l era)
243208
) =>
244209
EraTxBody era
245210
where
246211
-- | The body of a transaction.
247-
data TxBody (t :: TxType) era
248-
data KnownTxType (t :: TxType) era
249-
250-
txBodyType :: TxBody t era -> KnownTxType t era
212+
data TxBody (l :: TxLevel) era
251213

252-
mkBasicTxBody :: TxBody FullTx era
214+
mkBasicTxBody :: TxBody TopTx era
253215

254-
inputsTxBodyL :: Lens' (TxBody t era) (Set TxIn)
216+
inputsTxBodyL :: Lens' (TxBody l era) (Set TxIn)
255217

256-
outputsTxBodyL :: Lens' (TxBody t era) (StrictSeq (TxOut era))
218+
outputsTxBodyL :: Lens' (TxBody l era) (StrictSeq (TxOut era))
257219

258-
feeTxBodyL :: Lens' (TxBody FullTx era) Coin
220+
feeTxBodyL :: Lens' (TxBody TopTx era) Coin
259221

260-
withdrawalsTxBodyL :: Lens' (TxBody t era) Withdrawals
222+
withdrawalsTxBodyL :: Lens' (TxBody l era) Withdrawals
261223

262-
auxDataHashTxBodyL :: Lens' (TxBody t era) (StrictMaybe TxAuxDataHash)
224+
auxDataHashTxBodyL :: Lens' (TxBody l era) (StrictMaybe TxAuxDataHash)
263225

264226
-- | This getter will produce all inputs from the UTxO map that this transaction might
265227
-- spend, which ones will depend on the validity of the transaction itself. Starting in
266228
-- Alonzo this will include collateral inputs.
267-
spendableInputsTxBodyF :: SimpleGetter (TxBody t era) (Set TxIn)
229+
spendableInputsTxBodyF :: SimpleGetter (TxBody l era) (Set TxIn)
268230

269231
-- | This getter will produce all inputs from the UTxO map that this transaction is
270232
-- referencing, even if some of them cannot be spent by the transaction. For example
271233
-- starting with Babbage era it will also include reference inputs.
272-
allInputsTxBodyF :: SimpleGetter (TxBody t era) (Set TxIn)
234+
allInputsTxBodyF :: SimpleGetter (TxBody l era) (Set TxIn)
273235

274-
certsTxBodyL :: Lens' (TxBody t era) (StrictSeq (TxCert era))
236+
certsTxBodyL :: Lens' (TxBody l era) (StrictSeq (TxCert era))
275237

276238
-- | Compute the total deposits from the certificates in a TxBody.
277239
--
@@ -280,7 +242,7 @@ class
280242
PParams era ->
281243
-- | Check whether stake pool is registered or not
282244
(KeyHash 'StakePool -> Bool) ->
283-
TxBody t era ->
245+
TxBody l era ->
284246
Coin
285247
getTotalDepositsTxBody pp isPoolRegisted txBody =
286248
getTotalDepositsTxCerts pp isPoolRegisted (txBody ^. certsTxBodyL)
@@ -294,14 +256,14 @@ class
294256
(Credential 'Staking -> Maybe Coin) ->
295257
-- | Lookup current deposit for DRep credential if one is registered
296258
(Credential 'DRepRole -> Maybe Coin) ->
297-
TxBody t era ->
259+
TxBody l era ->
298260
Coin
299261
getTotalRefundsTxBody pp lookupStakingDeposit lookupDRepDeposit txBody =
300262
getTotalRefundsTxCerts pp lookupStakingDeposit lookupDRepDeposit (txBody ^. certsTxBodyL)
301263

302264
-- | This function is not used in the ledger rules. It is only used by the downstream
303265
-- tooling to figure out how many witnesses should be supplied for Genesis keys.
304-
getGenesisKeyHashCountTxBody :: TxBody FullTx era -> Int
266+
getGenesisKeyHashCountTxBody :: TxBody TopTx era -> Int
305267
getGenesisKeyHashCountTxBody _ = 0
306268

307269
-- | Abstract interface into specific fields of a `TxOut`
@@ -626,7 +588,7 @@ hashScript =
626588
-- | Indicates that an era supports segregated witnessing.
627589
--
628590
-- This class embodies an isomorphism between 'BlockBody era' and 'StrictSeq
629-
-- (Tx t era)', witnessed by the `txSeqBlockBodyL` lens.
591+
-- (Tx l era)', witnessed by the `txSeqBlockBodyL` lens.
630592
class
631593
( EraTx era
632594
, Eq (BlockBody era)
@@ -641,12 +603,12 @@ class
641603

642604
mkBasicBlockBody :: BlockBody era
643605

644-
txSeqBlockBodyL :: Lens' (BlockBody era) (StrictSeq (Tx FullTx era))
606+
txSeqBlockBodyL :: Lens' (BlockBody era) (StrictSeq (Tx TopTx era))
645607

646-
fromTxSeq :: BlockBody era -> StrictSeq (Tx FullTx era)
608+
fromTxSeq :: BlockBody era -> StrictSeq (Tx TopTx era)
647609
fromTxSeq = (^. txSeqBlockBodyL)
648610

649-
toTxSeq :: StrictSeq (Tx FullTx era) -> BlockBody era
611+
toTxSeq :: StrictSeq (Tx TopTx era) -> BlockBody era
650612
toTxSeq s = mkBasicBlockBody & txSeqBlockBodyL .~ s
651613

652614
-- | Get the block body hash from the BlockBody. Note that this is not a regular
@@ -669,14 +631,14 @@ class
669631
bBodySize :: forall era. EraBlockBody era => ProtVer -> BlockBody era -> Int
670632
bBodySize (ProtVer v _) = BS.length . serialize' v . encCBORGroup
671633

672-
txIdTx :: EraTx era => Tx t era -> TxId
634+
txIdTx :: EraTx era => Tx l era -> TxId
673635
txIdTx tx = txIdTxBody (tx ^. bodyTxL)
674636

675-
txIdTxBody :: EraTxBody era => TxBody t era -> TxId
637+
txIdTxBody :: EraTxBody era => TxBody l era -> TxId
676638
txIdTxBody = TxId . hashAnnotated
677639

678640
-- | txsize computes the length of the serialised bytes (actual size)
679-
wireSizeTxF :: forall era t. EraTx era => SimpleGetter (Tx t era) Word32
641+
wireSizeTxF :: forall era l. EraTx era => SimpleGetter (Tx l era) Word32
680642
wireSizeTxF =
681643
to $
682644
checkedFromIntegral
@@ -692,18 +654,18 @@ wireSizeTxF =
692654

693655
-- | Translate a transaction through its binary representation from previous to current era.
694656
binaryUpgradeTx ::
695-
forall era t.
696-
(Era era, ToCBOR (Tx t (PreviousEra era)), DecCBOR (Annotator (Tx t era))) =>
697-
Tx t (PreviousEra era) ->
698-
Except DecoderError (Tx t era)
657+
forall era l.
658+
(Era era, ToCBOR (Tx l (PreviousEra era)), DecCBOR (Annotator (Tx l era))) =>
659+
Tx l (PreviousEra era) ->
660+
Except DecoderError (Tx l era)
699661
binaryUpgradeTx = translateViaCBORAnnotator (eraProtVerLow @era) (withEraName @era "Tx")
700662

701663
-- | Translate a tx body through its binary representation from previous to current era.
702664
binaryUpgradeTxBody ::
703-
forall era t.
704-
(Era era, ToCBOR (TxBody t (PreviousEra era)), DecCBOR (Annotator (TxBody t era))) =>
705-
TxBody t (PreviousEra era) ->
706-
Except DecoderError (TxBody t era)
665+
forall era l.
666+
(Era era, ToCBOR (TxBody l (PreviousEra era)), DecCBOR (Annotator (TxBody l era))) =>
667+
TxBody l (PreviousEra era) ->
668+
Except DecoderError (TxBody l era)
707669
binaryUpgradeTxBody = translateViaCBORAnnotator (eraProtVerLow @era) (withEraName @era "TxBody")
708670

709671
-- | Translate tx witnesses through its binary representation from previous to current era.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
{-# LANGUAGE GADTs #-}
2+
{-# LANGUAGE MultiParamTypeClasses #-}
3+
{-# LANGUAGE ScopedTypeVariables #-}
4+
{-# LANGUAGE TypeApplications #-}
5+
{-# LANGUAGE TypeData #-}
6+
{-# LANGUAGE TypeFamilyDependencies #-}
7+
{-# LANGUAGE TypeOperators #-}
8+
{-# LANGUAGE UndecidableSuperClasses #-}
9+
10+
module Cardano.Ledger.Core.TxLevel (
11+
TxLevel (..),
12+
STxTopLevel (..),
13+
withSTxTopLevelM,
14+
STxBothLevels (..),
15+
withSTxBothLevels,
16+
EraTxLevel (..),
17+
HasEraTxLevel (..),
18+
mkSTxTopLevelM,
19+
mkSTxBothLevelsM,
20+
) where
21+
22+
import Cardano.Ledger.Core.Era (Era (..))
23+
import Data.Kind (Type)
24+
import Data.Typeable
25+
import GHC.Stack
26+
27+
type data TxLevel = TopTx | SubTx
28+
29+
data STxTopLevel (l :: TxLevel) era where
30+
STopTxOnly :: STxTopLevel TopTx era
31+
32+
withSTxTopLevelM ::
33+
forall l era a m. (Typeable l, Era era, MonadFail m) => (STxTopLevel l era -> m a) -> m a
34+
withSTxTopLevelM f =
35+
case eqT @l @TopTx of
36+
Just Refl -> f STopTxOnly
37+
Nothing -> fail $ "SubTx level is not supported in the " <> eraName @era <> " era"
38+
39+
data STxBothLevels (l :: TxLevel) era where
40+
STopTx :: STxBothLevels TopTx era
41+
SSubTx :: STxBothLevels SubTx era
42+
43+
withSTxBothLevels :: forall l era a. (Typeable l, HasCallStack) => (STxBothLevels l era -> a) -> a
44+
withSTxBothLevels f =
45+
case eqT @l @TopTx of
46+
Just Refl -> f STopTx
47+
Nothing -> case eqT @l @SubTx of
48+
Just Refl -> f SSubTx
49+
Nothing -> error $ "Impossible: Unrecognized TxLevel: " <> show (typeRep (Proxy @l))
50+
51+
class Era era => EraTxLevel era where
52+
type STxLevel (l :: TxLevel) era = (r :: Type) | r -> era
53+
type STxLevel l era = STxBothLevels l era
54+
55+
class EraTxLevel era => HasEraTxLevel (t :: TxLevel -> Type -> Type) era where
56+
toSTxLevel :: t l era -> STxLevel l era
57+
58+
mkSTxTopLevelM ::
59+
forall (l :: TxLevel) t m era.
60+
(Typeable l, MonadFail m, HasEraTxLevel t era, STxLevel l era ~ STxTopLevel l era) =>
61+
m (t TopTx era) -> m (t l era)
62+
mkSTxTopLevelM mkTopTx = do
63+
withSTxTopLevelM @l @era $ \level ->
64+
case level of
65+
STopTxOnly -> do
66+
res <- mkTopTx
67+
-- Here we tell the compiler that we only expect top level transactions in this function and
68+
-- any attempt to construct a sub transaction level will result in a compiler failure,
69+
-- instead of a trigger of `fail` in `MonadFail`.
70+
let _level = asTypeOf (toSTxLevel res) level
71+
pure res
72+
73+
mkSTxBothLevelsM ::
74+
forall (l :: TxLevel) t m era.
75+
(Typeable l, Monad m, HasEraTxLevel t era, STxLevel l era ~ STxBothLevels l era) =>
76+
m (t TopTx era) -> m (t SubTx era) -> m (t l era)
77+
mkSTxBothLevelsM mkTopTx mkSubTx =
78+
withSTxBothLevels @l $ \level -> do
79+
res <- case level of
80+
STopTx -> mkTopTx
81+
SSubTx -> mkSubTx
82+
-- Tell the compiler that we expect only `STxBothLevels` in this action
83+
let _level = asTypeOf (toSTxLevel res) level
84+
pure res

0 commit comments

Comments
 (0)