Skip to content

Commit 7fa043d

Browse files
amesgennfrisby
authored andcommitted
ouroboros-consensus-cardano: always use Conway ref scripts minfee in mempool
Even in Babbage! This is temporary.
1 parent f4c0208 commit 7fa043d

File tree

9 files changed

+157
-11
lines changed

9 files changed

+157
-11
lines changed

ouroboros-consensus-cardano/src/byron/Ouroboros/Consensus/Byron/Ledger/Mempool.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ instance LedgerSupportsMempool ByronBlock where
143143

144144
txForgetValidated = forgetValidatedByronTx
145145

146+
txRefScriptSize _ _ _ = 0
147+
146148
data instance TxId (GenTx ByronBlock)
147149
= ByronTxId !Utxo.TxId
148150
| ByronDlgId !Delegation.CertificateId

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Eras.hs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{-# LANGUAGE GADTs #-}
66
{-# LANGUAGE LambdaCase #-}
77
{-# LANGUAGE MultiParamTypeClasses #-}
8+
{-# LANGUAGE NumericUnderscores #-}
89
{-# LANGUAGE ScopedTypeVariables #-}
910
{-# LANGUAGE TypeApplications #-}
1011
{-# LANGUAGE TypeFamilies #-}
@@ -28,6 +29,7 @@ module Ouroboros.Consensus.Shelley.Eras (
2829
, StandardMary
2930
, StandardShelley
3031
-- * Shelley-based era
32+
, BabbageTxDict (..)
3133
, ConwayEraGovDict (..)
3234
, ShelleyBasedEra (..)
3335
, WrapTx (..)
@@ -45,6 +47,7 @@ import Cardano.Ledger.Alonzo (AlonzoEra)
4547
import qualified Cardano.Ledger.Alonzo.Rules as Alonzo
4648
import qualified Cardano.Ledger.Alonzo.Translation as Alonzo
4749
import qualified Cardano.Ledger.Alonzo.Tx as Alonzo
50+
import qualified Cardano.Ledger.Api as SL
4851
import qualified Cardano.Ledger.Api.Era as L
4952
import Cardano.Ledger.Babbage (BabbageEra)
5053
import qualified Cardano.Ledger.Babbage.Rules as Babbage
@@ -57,6 +60,8 @@ import qualified Cardano.Ledger.Conway.Rules as Conway
5760
import qualified Cardano.Ledger.Conway.Rules as SL
5861
(ConwayLedgerPredFailure (..))
5962
import qualified Cardano.Ledger.Conway.Translation as Conway
63+
import qualified Cardano.Ledger.Conway.Tx as SL
64+
import qualified Cardano.Ledger.Conway.UTxO as SL
6065
import Cardano.Ledger.Core as Core
6166
import Cardano.Ledger.Crypto (StandardCrypto)
6267
import Cardano.Ledger.Keys (DSignable, Hash)
@@ -68,11 +73,13 @@ import Cardano.Ledger.Shelley.Core as Core
6873
import qualified Cardano.Ledger.Shelley.LedgerState as SL
6974
import qualified Cardano.Ledger.Shelley.Rules as SL
7075
import qualified Cardano.Ledger.Shelley.Transition as SL
76+
import qualified Cardano.Ledger.Val as SL
7177
import qualified Cardano.Protocol.TPraos.API as SL
7278
import Control.Monad.Except
7379
import Control.State.Transition (PredicateFailure)
7480
import Data.Data (Proxy (Proxy))
7581
import Data.List.NonEmpty (NonEmpty ((:|)))
82+
import Lens.Micro ((^.))
7683
import NoThunks.Class (NoThunks)
7784
import Ouroboros.Consensus.Ledger.SupportsMempool
7885
(WhetherToIntervene (..))
@@ -162,6 +169,16 @@ class ( Core.EraSegWits era
162169
-- | Whether the era has an instance of 'CG.ConwayEraGov'
163170
getConwayEraGovDict :: proxy era -> Maybe (ConwayEraGovDict era)
164171

172+
getBabbageTxDict :: proxy era -> Maybe (BabbageTxDict era)
173+
174+
data BabbageTxDict era where
175+
BabbageTxDict ::
176+
SL.BabbageEraTxBody era
177+
=> (Integer -> Integer -> SL.ApplyTxError era)
178+
-- ^ Construct an arbitrary ledger error with two integers as its
179+
-- payload.
180+
-> BabbageTxDict era
181+
165182
data ConwayEraGovDict era where
166183
ConwayEraGovDict :: CG.ConwayEraGov era => ConwayEraGovDict era
167184

@@ -172,7 +189,7 @@ isBeforeConway _ =
172189
-- | The default implementation of 'applyShelleyBasedTx', a thin wrapper around
173190
-- 'SL.applyTx'
174191
defaultApplyShelleyBasedTx ::
175-
ShelleyBasedEra era
192+
forall era. ShelleyBasedEra era
176193
=> SL.Globals
177194
-> SL.LedgerEnv era
178195
-> SL.LedgerState era
@@ -183,12 +200,51 @@ defaultApplyShelleyBasedTx ::
183200
( SL.LedgerState era
184201
, SL.Validated (Core.Tx era)
185202
)
186-
defaultApplyShelleyBasedTx globals ledgerEnv mempoolState _wti tx =
203+
defaultApplyShelleyBasedTx globals ledgerEnv mempoolState _wti tx = do
204+
refScriptPredicate
187205
SL.applyTx
188206
globals
189207
ledgerEnv
190208
mempoolState
191209
tx
210+
where
211+
refScriptPredicate = case getBabbageTxDict (Proxy @era) of
212+
Nothing -> pure ()
213+
Just (BabbageTxDict mkError)
214+
-- Reject it if it has more than 100 kibibytes of ref script.
215+
| refScriptsSize > totalRefScriptsSizeLimit
216+
-> throwError $ mkError
217+
-- As we are reusing an existing error message, we add a large
218+
-- number to make users running into this are productively irritated
219+
-- and post this error message somewhere where they can receive
220+
-- help/context.
221+
(toInteger refScriptsSize + 1_000_000_000)
222+
(toInteger totalRefScriptsSizeLimit + 1_000_000_000)
223+
-- Reject it if it has more than 50 kibibytes of ref script and does not
224+
-- satisfy an additional fee as calculated in the table below.
225+
| refScriptsSize > freeOfChargeRefScriptsBytes
226+
, actualFee < expectedFee
227+
-> throwError $ mkError
228+
-- See above for why we add a large constant.
229+
(SL.unCoin actualFee + 100_000_000)
230+
(SL.unCoin expectedFee + 100_000_000)
231+
| otherwise -> pure ()
232+
where
233+
totalRefScriptsSizeLimit :: Int
234+
totalRefScriptsSizeLimit = 100 * 1024
235+
236+
freeOfChargeRefScriptsBytes :: Int
237+
freeOfChargeRefScriptsBytes = 50 * 1024
238+
239+
actualFee = tx ^. SL.bodyTxL . SL.feeTxBodyL
240+
expectedFee = minFee SL.<+> refScriptsFee
241+
where
242+
minFee = SL.getMinFeeTx (SL.ledgerPp ledgerEnv) tx 0
243+
refScriptsFee = SL.tierRefScriptFee 1.2 25600 15 refScriptsSize
244+
245+
refScriptsSize = SL.txNonDistinctRefScriptsSize utxo tx
246+
247+
utxo = SL.utxosUtxo . SL.lsUTxOState $ mempoolState
192248

193249
defaultGetConwayEraGovDict :: proxy era -> Maybe (ConwayEraGovDict era)
194250
defaultGetConwayEraGovDict _ = Nothing
@@ -199,34 +255,52 @@ instance (SL.PraosCrypto c, DSignable c (Hash c EraIndependentTxBody))
199255

200256
getConwayEraGovDict = defaultGetConwayEraGovDict
201257

258+
getBabbageTxDict _ = Nothing
259+
202260
instance (SL.PraosCrypto c, DSignable c (Hash c EraIndependentTxBody))
203261
=> ShelleyBasedEra (AllegraEra c) where
204262
applyShelleyBasedTx = defaultApplyShelleyBasedTx
205263

206264
getConwayEraGovDict = defaultGetConwayEraGovDict
207265

266+
getBabbageTxDict _ = Nothing
267+
208268
instance (SL.PraosCrypto c, DSignable c (Hash c EraIndependentTxBody))
209269
=> ShelleyBasedEra (MaryEra c) where
210270
applyShelleyBasedTx = defaultApplyShelleyBasedTx
211271

212272
getConwayEraGovDict = defaultGetConwayEraGovDict
213273

274+
getBabbageTxDict _ = Nothing
275+
214276
instance (SL.PraosCrypto c, DSignable c (Hash c EraIndependentTxBody))
215277
=> ShelleyBasedEra (AlonzoEra c) where
216278
applyShelleyBasedTx = applyAlonzoBasedTx
217279

218280
getConwayEraGovDict = defaultGetConwayEraGovDict
219281

282+
getBabbageTxDict _ = Nothing
283+
220284
instance (Praos.PraosCrypto c) => ShelleyBasedEra (BabbageEra c) where
221285
applyShelleyBasedTx = applyAlonzoBasedTx
222286

223287
getConwayEraGovDict = defaultGetConwayEraGovDict
224288

289+
getBabbageTxDict _ = Just $ BabbageTxDict $ \a b ->
290+
SL.ApplyTxError
291+
$ pure
292+
$ SL.UtxowFailure
293+
$ Babbage.UtxoFailure
294+
$ Babbage.AlonzoInBabbageUtxoPredFailure
295+
$ Alonzo.MaxTxSizeUTxO a b
296+
225297
instance (Praos.PraosCrypto c) => ShelleyBasedEra (ConwayEra c) where
226298
applyShelleyBasedTx = applyAlonzoBasedTx
227299

228300
getConwayEraGovDict _ = Just ConwayEraGovDict
229301

302+
getBabbageTxDict _ = Nothing
303+
230304
applyAlonzoBasedTx :: forall era.
231305
( ShelleyBasedEra era,
232306
SupportsTwoPhaseValidation era,

ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import Cardano.Ledger.Alonzo.Tx (totExUnits)
4242
import Cardano.Ledger.Binary (Annotator (..), DecCBOR (..),
4343
EncCBOR (..), FromCBOR (..), FullByteString (..),
4444
ToCBOR (..), toPlainDecoder)
45+
import qualified Cardano.Ledger.Conway.UTxO as SL
4546
import qualified Cardano.Ledger.Core as SL (txIdTxBody)
4647
import Cardano.Ledger.Crypto (Crypto)
4748
import qualified Cardano.Ledger.SafeHash as SL
@@ -147,6 +148,12 @@ instance ShelleyCompatible proto era
147148

148149
txForgetValidated (ShelleyValidatedTx txid vtx) = ShelleyTx txid (SL.extractTx vtx)
149150

151+
txRefScriptSize _cfg st (ShelleyTx _ tx) = case getBabbageTxDict (Proxy @era) of
152+
Nothing -> 0
153+
Just BabbageTxDict{} -> SL.txNonDistinctRefScriptsSize utxo tx
154+
where
155+
utxo = SL.getUTxO . tickedShelleyLedgerState $ st
156+
150157
mkShelleyTx :: forall era proto. ShelleyBasedEra era => Tx era -> GenTx (ShelleyBlock proto era)
151158
mkShelleyTx tx = ShelleyTx (SL.txIdTxBody @era (tx ^. bodyTxL)) tx
152159

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/HardFork/Combinator/Mempool.hs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
{-# LANGUAGE FlexibleContexts #-}
66
{-# LANGUAGE FlexibleInstances #-}
77
{-# LANGUAGE GADTs #-}
8+
{-# LANGUAGE NamedFieldPuns #-}
89
{-# LANGUAGE RankNTypes #-}
910
{-# LANGUAGE RecordWildCards #-}
1011
{-# LANGUAGE ScopedTypeVariables #-}
@@ -124,6 +125,40 @@ instance CanHardFork xs => LedgerSupportsMempool (HardForkBlock xs) where
124125
. getOneEraValidatedGenTx
125126
. getHardForkValidatedGenTx
126127

128+
txRefScriptSize cfg st tx = case matchPolyTx injs tx' hardForkState of
129+
Left {} ->
130+
-- This is ugly/adhoc, but fine, as in the mempool, we only call
131+
-- txRefScriptSize after applyTx (which internall also calls
132+
-- matchPolyTx), so this case is unreachable.
133+
0
134+
Right matched ->
135+
hcollapse
136+
$ hczipWith proxySingle
137+
(\(WrapLedgerConfig eraCfg) (Pair eraTx (Comp eraSt)) ->
138+
K $ txRefScriptSize eraCfg eraSt eraTx)
139+
cfgs
140+
(State.tip matched)
141+
where
142+
HardForkLedgerConfig {
143+
hardForkLedgerConfigPerEra
144+
, hardForkLedgerConfigShape
145+
} = cfg
146+
TickedHardForkLedgerState transition hardForkState = st
147+
tx' = getOneEraGenTx . getHardForkGenTx $ tx
148+
149+
pcfgs = getPerEraLedgerConfig hardForkLedgerConfigPerEra
150+
cfgs = hcmap proxySingle (completeLedgerConfig'' ei) pcfgs
151+
ei = State.epochInfoPrecomputedTransitionInfo
152+
hardForkLedgerConfigShape
153+
transition
154+
hardForkState
155+
156+
injs :: InPairs (InjectPolyTx GenTx) xs
157+
injs =
158+
InPairs.hmap
159+
(\(Pair2 injTx _injValidatedTx) -> injTx)
160+
(InPairs.requiringBoth cfgs hardForkInjectTxs)
161+
127162
-- | A private type used only to clarify the parameterization of 'applyHelper'
128163
data ApplyHelperMode :: (Type -> Type) -> Type where
129164
ModeApply :: ApplyHelperMode GenTx

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/Dual.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,12 @@ instance Bridge m a => LedgerSupportsMempool (DualBlock m a) where
624624
, vDualGenTxBridge
625625
} = vtx
626626

627+
txRefScriptSize cfg st tx =
628+
txRefScriptSize
629+
(dualLedgerConfigMain cfg)
630+
(tickedDualLedgerStateMain st)
631+
(dualGenTxMain tx)
632+
627633
-- We don't need a pair of IDs, as long as we can unique ID the transaction
628634
newtype instance TxId (GenTx (DualBlock m a)) = DualGenTxId {
629635
dualGenTxIdMain :: GenTxId m

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/SupportsMempool.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ class ( UpdateLedger blk
127127
-- | Discard the evidence that transaction has been previously validated
128128
txForgetValidated :: Validated (GenTx blk) -> GenTx blk
129129

130+
txRefScriptSize :: LedgerConfig blk -> TickedLedgerState blk -> GenTx blk -> Int
131+
130132
-- | A generalized transaction, 'GenTx', identifier.
131133
data family TxId tx :: Type
132134

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Impl/Common.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module Ouroboros.Consensus.Mempool.Impl.Common (
1313
-- * Internal state
1414
InternalState (..)
1515
, isMempoolSize
16+
, isTotalRefScriptSize
1617
-- * Mempool environment
1718
, MempoolEnv (..)
1819
, initMempoolEnv
@@ -139,6 +140,9 @@ deriving instance ( NoThunks (Validated (GenTx blk))
139140
isMempoolSize :: InternalState blk -> MempoolSize
140141
isMempoolSize = TxSeq.toMempoolSize . isTxs
141142

143+
isTotalRefScriptSize :: InternalState blk -> Int
144+
isTotalRefScriptSize = TxSeq.toRefScriptSize . isTxs
145+
142146
initInternalState ::
143147
LedgerSupportsMempool blk
144148
=> MempoolCapacityBytesOverride
@@ -340,6 +344,7 @@ extendVRNew cfg txSize wti tx vr = assert (isNothing vrNewValid) $
340344
Right (st', vtx) ->
341345
( Right vtx
342346
, vr { vrValid = vrValid :> TxTicket vtx nextTicketNo (txSize tx)
347+
(txRefScriptSize cfg vrAfter tx)
343348
, vrValidTxIds = Set.insert (txId tx) vrValidTxIds
344349
, vrNewValid = Just vtx
345350
, vrAfter = st'

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/TxSeq.hs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ module Ouroboros.Consensus.Mempool.TxSeq (
2222
, splitAfterTxSize
2323
, toList
2424
, toMempoolSize
25+
, toRefScriptSize
2526
, toTuples
2627
, zeroTicketNo
2728
-- * Reference implementations for testing
@@ -63,6 +64,7 @@ data TxTicket tx = TxTicket
6364
, txTicketTxSizeInBytes :: !TxSizeInBytes
6465
-- ^ The byte size of the transaction ('txTicketTx') associated with this
6566
-- ticket.
67+
, txTicketRefScriptSize :: !Int
6668
} deriving (Eq, Show, Generic, NoThunks)
6769

6870
-- | The mempool is a sequence of transactions with their ticket numbers and
@@ -102,25 +104,27 @@ instance Foldable TxSeq where
102104
-- instance.
103105
--
104106
data TxSeqMeasure = TxSeqMeasure {
105-
mMinTicket :: !TicketNo,
106-
mMaxTicket :: !TicketNo,
107-
mSizeBytes :: !TxSizeInBytes,
108-
mSize :: !Int
107+
mMinTicket :: !TicketNo,
108+
mMaxTicket :: !TicketNo,
109+
mSizeBytes :: !TxSizeInBytes,
110+
mSize :: !Int,
111+
mRefScriptSize :: !Int
109112
}
110113
deriving Show
111114

112115
instance FingerTree.Measured TxSeqMeasure (TxTicket tx) where
113-
measure (TxTicket _ tno tsz) = TxSeqMeasure tno tno tsz 1
116+
measure (TxTicket _ tno tsz trssz) = TxSeqMeasure tno tno tsz 1 trssz
114117

115118
instance Semigroup TxSeqMeasure where
116119
vl <> vr = TxSeqMeasure
117120
(mMinTicket vl `min` mMinTicket vr)
118121
(mMaxTicket vl `max` mMaxTicket vr)
119122
(mSizeBytes vl + mSizeBytes vr)
120123
(mSize vl + mSize vr)
124+
(mRefScriptSize vl + mRefScriptSize vr)
121125

122126
instance Monoid TxSeqMeasure where
123-
mempty = TxSeqMeasure maxBound minBound 0 0
127+
mempty = TxSeqMeasure maxBound minBound 0 0 0
124128
mappend = (<>)
125129

126130
-- | A helper function for the ':>' pattern.
@@ -171,8 +175,8 @@ lookupByTicketNo :: TxSeq tx -> TicketNo -> Maybe tx
171175
lookupByTicketNo (TxSeq txs) n =
172176
case FingerTree.search (\ml mr -> mMaxTicket ml >= n
173177
&& mMinTicket mr > n) txs of
174-
FingerTree.Position _ (TxTicket tx n' _) _ | n' == n -> Just tx
175-
_ -> Nothing
178+
FingerTree.Position _ (TxTicket tx n' _ _) _ | n' == n -> Just tx
179+
_ -> Nothing
176180

177181
-- | \( O(\log(n)) \). Split the sequence of transactions into two parts
178182
-- based on the given 'TicketNo'. The first part has transactions with tickets
@@ -244,3 +248,8 @@ toMempoolSize (TxSeq ftree) = MempoolSize
244248
}
245249
where
246250
TxSeqMeasure { mSizeBytes, mSize } = FingerTree.measure ftree
251+
252+
toRefScriptSize :: TxSeq tx -> Int
253+
toRefScriptSize (TxSeq ftree) = mRefScriptSize
254+
where
255+
TxSeqMeasure { mRefScriptSize } = FingerTree.measure ftree

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,15 @@ pureTryAddTx ::
181181
-- ^ The current internal state of the mempool.
182182
-> TryAddTx blk
183183
pureTryAddTx cfg txSize wti tx is
184+
-- We add the transaction if there is at least one byte free left in the
185+
-- mempool, and...
184186
| let curSize = msNumBytes $ isMempoolSize is
185187
, curSize < getMempoolCapacityBytes (isCapacity is)
186-
= -- We add the transaction if there is at least one byte free left in the mempool.
188+
-- ... if the mempool has less than 2.5 mebibytes of ref scripts.
189+
, let maxTotalRefScriptSize = 5 * 512 * 1024 -- 2.5 Mebibytes
190+
curTotalRefScriptSize = isTotalRefScriptSize is
191+
, curTotalRefScriptSize Prelude.< maxTotalRefScriptSize
192+
=
187193
case eVtx of
188194
-- We only extended the ValidationResult with a single transaction
189195
-- ('tx'). So if it's not in 'vrInvalid', it must be in 'vrNewValid'.

0 commit comments

Comments
 (0)