From 0a4dedfaa93394c113f22c85cbf9a3e6c58beb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20W=C3=B3jtowicz?= Date: Mon, 5 Aug 2024 20:50:26 +0200 Subject: [PATCH 1/2] Added method to compute over-the-wire CBOR encoded transaction size --- .../impl/src/Cardano/Ledger/Allegra/Tx.hs | 4 ++++ .../impl/src/Cardano/Ledger/Alonzo/Tx.hs | 22 ++++++++++++++++++- .../impl/src/Cardano/Ledger/Babbage/Tx.hs | 3 +++ .../impl/src/Cardano/Ledger/Conway/Tx.hs | 4 ++++ eras/mary/impl/src/Cardano/Ledger/Mary/Tx.hs | 4 ++++ .../impl/src/Cardano/Ledger/Shelley/Tx.hs | 13 +++++++++++ .../src/Cardano/Ledger/Core.hs | 6 ++++- 7 files changed, 54 insertions(+), 2 deletions(-) diff --git a/eras/allegra/impl/src/Cardano/Ledger/Allegra/Tx.hs b/eras/allegra/impl/src/Cardano/Ledger/Allegra/Tx.hs index 23da633d776..229659c27c2 100644 --- a/eras/allegra/impl/src/Cardano/Ledger/Allegra/Tx.hs +++ b/eras/allegra/impl/src/Cardano/Ledger/Allegra/Tx.hs @@ -33,6 +33,7 @@ import Cardano.Ledger.Shelley.Tx ( mkBasicShelleyTx, shelleyMinFeeTx, sizeShelleyTxF, + wireSizeShelleyTxF, witsShelleyTxL, ) import qualified Data.Set as Set (map) @@ -59,6 +60,9 @@ instance Crypto c => EraTx (AllegraEra c) where sizeTxF = sizeShelleyTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeShelleyTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateTimelock {-# INLINE validateNativeScript #-} diff --git a/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs b/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs index 52ea88c6c00..6dd7f58fc4f 100644 --- a/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs +++ b/eras/alonzo/impl/src/Cardano/Ledger/Alonzo/Tx.hs @@ -49,6 +49,7 @@ module Cardano.Ledger.Alonzo.Tx ( witsAlonzoTxL, auxDataAlonzoTxL, sizeAlonzoTxF, + wireSizeAlonzoTxF, isValidAlonzoTxL, txdats', txscripts', @@ -146,6 +147,7 @@ import Data.Maybe.Strict ( import Data.Set (Set) import qualified Data.Set as Set import Data.Typeable (Typeable) +import Data.Word (Word32) import GHC.Generics (Generic) import Lens.Micro hiding (set) import NoThunks.Class (NoThunks) @@ -189,6 +191,9 @@ instance Crypto c => EraTx (AlonzoEra c) where sizeTxF = sizeAlonzoTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeAlonzoTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateTimelock {-# INLINE validateNativeScript #-} @@ -235,7 +240,7 @@ auxDataAlonzoTxL :: Lens' (AlonzoTx era) (StrictMaybe (TxAuxData era)) auxDataAlonzoTxL = lens auxiliaryData (\tx txTxAuxData -> tx {auxiliaryData = txTxAuxData}) {-# INLINEABLE auxDataAlonzoTxL #-} --- | txsize computes the length of the serialised bytes +-- | txsize computes the length of the serialised bytes (for estimations) sizeAlonzoTxF :: forall era. EraTx era => SimpleGetter (AlonzoTx era) Integer sizeAlonzoTxF = to $ @@ -245,6 +250,21 @@ sizeAlonzoTxF = . toCBORForSizeComputation {-# INLINEABLE sizeAlonzoTxF #-} +-- | txsize computes the length of the serialised bytes (actual size) +wireSizeAlonzoTxF :: forall era. EraTx era => SimpleGetter (AlonzoTx era) Word32 +wireSizeAlonzoTxF = + to $ + checkedFromIntegral + . LBS.length + . serialize (eraProtVerLow @era) + . encCBOR + where + checkedFromIntegral n = + if n <= fromIntegral (maxBound :: Word32) + then fromIntegral n + else error $ "Impossible: Size of the transaction is too big: " ++ show n +{-# INLINEABLE wireSizeAlonzoTxF #-} + isValidAlonzoTxL :: Lens' (AlonzoTx era) IsValid isValidAlonzoTxL = lens isValid (\tx valid -> tx {isValid = valid}) {-# INLINEABLE isValidAlonzoTxL #-} diff --git a/eras/babbage/impl/src/Cardano/Ledger/Babbage/Tx.hs b/eras/babbage/impl/src/Cardano/Ledger/Babbage/Tx.hs index 03180d62eeb..472347aae2e 100644 --- a/eras/babbage/impl/src/Cardano/Ledger/Babbage/Tx.hs +++ b/eras/babbage/impl/src/Cardano/Ledger/Babbage/Tx.hs @@ -50,6 +50,9 @@ instance Crypto c => EraTx (BabbageEra c) where sizeTxF = sizeAlonzoTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeAlonzoTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateTimelock {-# INLINE validateNativeScript #-} diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Tx.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Tx.hs index b44038cc36b..0976f8065ed 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Tx.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Tx.hs @@ -21,6 +21,7 @@ import Cardano.Ledger.Alonzo.Tx ( isValidAlonzoTxL, mkBasicAlonzoTx, sizeAlonzoTxF, + wireSizeAlonzoTxF, witsAlonzoTxL, ) import Cardano.Ledger.Alonzo.TxSeq ( @@ -65,6 +66,9 @@ instance Crypto c => EraTx (ConwayEra c) where sizeTxF = sizeAlonzoTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeAlonzoTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateTimelock {-# INLINE validateNativeScript #-} diff --git a/eras/mary/impl/src/Cardano/Ledger/Mary/Tx.hs b/eras/mary/impl/src/Cardano/Ledger/Mary/Tx.hs index d9e166e9f52..9fa175fac62 100644 --- a/eras/mary/impl/src/Cardano/Ledger/Mary/Tx.hs +++ b/eras/mary/impl/src/Cardano/Ledger/Mary/Tx.hs @@ -23,6 +23,7 @@ import Cardano.Ledger.Shelley.Tx ( mkBasicShelleyTx, shelleyMinFeeTx, sizeShelleyTxF, + wireSizeShelleyTxF, witsShelleyTxL, ) @@ -47,6 +48,9 @@ instance Crypto c => EraTx (MaryEra c) where sizeTxF = sizeShelleyTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeShelleyTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateTimelock {-# INLINE validateNativeScript #-} diff --git a/eras/shelley/impl/src/Cardano/Ledger/Shelley/Tx.hs b/eras/shelley/impl/src/Cardano/Ledger/Shelley/Tx.hs index baced876e01..c61af5a8f75 100644 --- a/eras/shelley/impl/src/Cardano/Ledger/Shelley/Tx.hs +++ b/eras/shelley/impl/src/Cardano/Ledger/Shelley/Tx.hs @@ -28,6 +28,7 @@ module Cardano.Ledger.Shelley.Tx ( witsShelleyTxL, auxDataShelleyTxL, sizeShelleyTxF, + wireSizeShelleyTxF, segwitTx, mkBasicShelleyTx, shelleyMinFeeTx, @@ -86,6 +87,7 @@ import Data.Maybe.Strict ( import Data.Set (Set) import qualified Data.Set as Set import Data.Typeable (Typeable) +import Data.Word (Word32) import GHC.Generics (Generic) import Lens.Micro (Lens', SimpleGetter, lens, to, (^.)) import NoThunks.Class (NoThunks (..)) @@ -168,6 +170,14 @@ sizeShelleyTxF :: Era era => SimpleGetter (ShelleyTx era) Integer sizeShelleyTxF = to (\(TxConstr (Memo _ bytes)) -> fromIntegral $ SBS.length bytes) {-# INLINEABLE sizeShelleyTxF #-} +wireSizeShelleyTxF :: Era era => SimpleGetter (ShelleyTx era) Word32 +wireSizeShelleyTxF = to $ \(TxConstr (Memo _ bytes)) -> + let n = SBS.length bytes + in if n <= fromIntegral (maxBound :: Word32) + then fromIntegral n + else error $ "Impossible: Size of the transaction is too big: " ++ show n +{-# INLINEABLE wireSizeShelleyTxF #-} + mkShelleyTx :: EraTx era => ShelleyTxRaw era -> ShelleyTx era mkShelleyTx = TxConstr . memoBytes . encodeShelleyTxRaw {-# INLINEABLE mkShelleyTx #-} @@ -200,6 +210,9 @@ instance Crypto c => EraTx (ShelleyEra c) where sizeTxF = sizeShelleyTxF {-# INLINE sizeTxF #-} + wireSizeTxF = wireSizeShelleyTxF + {-# INLINE wireSizeTxF #-} + validateNativeScript = validateMultiSig {-# INLINE validateNativeScript #-} diff --git a/libs/cardano-ledger-core/src/Cardano/Ledger/Core.hs b/libs/cardano-ledger-core/src/Cardano/Ledger/Core.hs index e2fe27b18a9..3503623dec8 100644 --- a/libs/cardano-ledger-core/src/Cardano/Ledger/Core.hs +++ b/libs/cardano-ledger-core/src/Cardano/Ledger/Core.hs @@ -118,7 +118,7 @@ import Data.Maybe.Strict (StrictMaybe) import Data.Sequence.Strict (StrictSeq) import Data.Set (Set) import Data.Void (Void) -import Data.Word (Word64) +import Data.Word (Word32, Word64) import GHC.Stack (HasCallStack) import Lens.Micro import NoThunks.Class (NoThunks) @@ -153,8 +153,12 @@ class auxDataTxL :: Lens' (Tx era) (StrictMaybe (AuxiliaryData era)) + -- | For fee calculation and estimations of impact on block space sizeTxF :: SimpleGetter (Tx era) Integer + -- | For end use by eg. diffusion layer in transaction submission protocol + wireSizeTxF :: SimpleGetter (Tx era) Word32 + -- | Using information from the transaction validate the supplied native script. validateNativeScript :: Tx era -> NativeScript era -> Bool From d1b8e6ceb17fecbdcc7b24966921a1d702a2ef57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20W=C3=B3jtowicz?= Date: Mon, 5 Aug 2024 20:47:32 +0200 Subject: [PATCH 2/2] Update changelog --- eras/alonzo/impl/CHANGELOG.md | 2 ++ eras/shelley/impl/CHANGELOG.md | 2 ++ libs/cardano-ledger-core/CHANGELOG.md | 1 + 3 files changed, 5 insertions(+) diff --git a/eras/alonzo/impl/CHANGELOG.md b/eras/alonzo/impl/CHANGELOG.md index 14735c39f9d..e35331f5ee3 100644 --- a/eras/alonzo/impl/CHANGELOG.md +++ b/eras/alonzo/impl/CHANGELOG.md @@ -2,6 +2,8 @@ ## 1.10.1.0 +* Added `wireSizeAlonzoTxF` + ### `testlib` * Export `fixupRedeemerIndices` from `Alonzo.ImpTest` diff --git a/eras/shelley/impl/CHANGELOG.md b/eras/shelley/impl/CHANGELOG.md index c27f22964f3..3db8cc09404 100644 --- a/eras/shelley/impl/CHANGELOG.md +++ b/eras/shelley/impl/CHANGELOG.md @@ -4,6 +4,8 @@ * Add `translateToShelleyLedgerStateFromUtxo` +* Added `wireSizeShelleyTxF` + ### `testlib` * Add `submitFailingTxM` diff --git a/libs/cardano-ledger-core/CHANGELOG.md b/libs/cardano-ledger-core/CHANGELOG.md index a84ca24b343..008704a8de2 100644 --- a/libs/cardano-ledger-core/CHANGELOG.md +++ b/libs/cardano-ledger-core/CHANGELOG.md @@ -12,6 +12,7 @@ * Change default implementation of `translateEra` * Add `EraGenesis` and `Genesis` type family. New `NoGenesis` type to be used for eras that do not have a genesis file * Move `ensureMinCoinTxOut` from `cardano-ledger-api` to `Cardano.Ledger.Tools` +* Add `wireSizeTxF` to `EraTx` class ### `testlib`