Skip to content

Commit 604c811

Browse files
committed
TOSQUASH a round of polishing
1 parent df2bd10 commit 604c811

File tree

7 files changed

+109
-70
lines changed

7 files changed

+109
-70
lines changed

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module Ouroboros.Consensus.Mempool (
33
-- * Mempool API
44
-- ** Mempool
55
Mempool (..)
6+
, MempoolCapacity (..)
7+
, worstCaseCapacity
68
-- ** Transaction adding
79
, MempoolAddTxResult (..)
810
, addLocalTxs
@@ -40,9 +42,10 @@ module Ouroboros.Consensus.Mempool (
4042

4143
import Ouroboros.Consensus.Mempool.API (ForgeLedgerState (..),
4244
Mempool (..), MempoolAddTxResult (..),
43-
MempoolSnapshot (..), TicketNo, TxSizeInBytes,
44-
TxTicket (..), addLocalTxs, addTxs, isMempoolTxAdded,
45-
isMempoolTxRejected, mempoolTxAddedToMaybe, snapshotTxs,
45+
MempoolCapacity (..), MempoolSnapshot (..), TicketNo,
46+
TxSizeInBytes, TxTicket (..), addLocalTxs, addTxs,
47+
isMempoolTxAdded, isMempoolTxRejected,
48+
mempoolTxAddedToMaybe, snapshotTxs, worstCaseCapacity,
4649
zeroTicketNo)
4750
import Ouroboros.Consensus.Mempool.Capacity (MempoolSize (..),
4851
TxOverrides (..), applyOverrides, mkOverrides,

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

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
{-# LANGUAGE DeriveGeneric #-}
12
{-# LANGUAGE FlexibleContexts #-}
23
{-# LANGUAGE ScopedTypeVariables #-}
34
{-# LANGUAGE StandaloneDeriving #-}
5+
{-# LANGUAGE TypeApplications #-}
46
{-# LANGUAGE UndecidableInstances #-}
57

68
-- | Exposes the @'Mempool'@ datatype which captures the public API of the
@@ -12,6 +14,8 @@
1214
module Ouroboros.Consensus.Mempool.API (
1315
-- * Mempool
1416
Mempool (..)
17+
, MempoolCapacity (..)
18+
, worstCaseCapacity
1519
-- * Transaction adding
1620
, AddTxOnBehalfOf (..)
1721
, MempoolAddTxResult (..)
@@ -32,7 +36,10 @@ module Ouroboros.Consensus.Mempool.API (
3236
, zeroTicketNo
3337
) where
3438

39+
import Data.DerivingVia (InstantiatedAt (..))
3540
import qualified Data.Measure as Measure
41+
import Data.Semigroup (stimes)
42+
import GHC.Generics (Generic)
3643
import Ouroboros.Consensus.Block (SlotNo)
3744
import Ouroboros.Consensus.Ledger.Abstract
3845
import Ouroboros.Consensus.Ledger.SupportsMempool
@@ -198,18 +205,64 @@ data Mempool m blk = Mempool {
198205
-- This does not update the state of the mempool.
199206
, getSnapshotFor :: ForgeLedgerState blk -> STM m (MempoolSnapshot blk)
200207

201-
-- | Get the mempool's capacity.
208+
-- | Get the current 'MempoolCapacity'.
202209
--
203-
-- Note that the capacity of the Mempool, unless it is overridden, can
204-
-- dynamically change when the ledger state is updated.
205-
--
206-
-- When the capacity happens to shrink at some point, we /do not/ remove
207-
-- transactions from the Mempool to satisfy this new lower limit.
208-
-- Instead, we treat it the same way as a Mempool which is /at/
209-
-- capacity, i.e., we won't admit new transactions until some have been
210-
-- removed because they have become invalid.
211-
, getCapacity :: STM m (TxMeasure blk, Int)
210+
-- This might change if the mempool is synchronized with the node's
211+
-- latest selection.
212+
, getCapacity :: STM m (MempoolCapacity blk)
213+
}
214+
215+
-- | The capacity of a mempool.
216+
--
217+
-- When the capacity happens to shrink at some point, we /do not/ remove
218+
-- transactions from the mempool to satisfy this new lower limit. Instead, we
219+
-- treat it the same way as a mempool which is /at/ capacity, ie we won't admit
220+
-- new transactions until some have been removed because they have become
221+
-- invalid.
222+
--
223+
-- Cardano governance tends to only change this limit based on ticking across
224+
-- some slot boundary. The mempool cannot know the slot of whatever block these
225+
-- transactions will end up in. And so we cannot know what the actual block
226+
-- capacity will be.
227+
--
228+
-- As long as the block capacity is not changed severely and abruptly, then it
229+
-- is an effective approximation to use the capacity of whatever ledger state
230+
-- the mempool was most recently synchronized against.
231+
data MempoolCapacity blk = MempoolCapacity {
232+
-- | The anticipated limits of the next block to be minted.
233+
mcBlockCapacity :: !(TxMeasure blk)
234+
235+
-- | How many 'mcBlockCapacity'-maximized blocks could be cut from the
236+
-- sequence of txs in a full mempool.
237+
, mcBlockMultiplicity :: !Int
212238
}
239+
deriving Generic
240+
241+
-- | The largest the mempool could be along each of the dimensions.
242+
--
243+
-- EG if the mempool contained only transactions that only had one non-trivial
244+
-- component of their size measures, then that component of the mempool's
245+
-- capacity could be up to 'mcBlockMultiplicity' times that component of
246+
-- 'mcBlockCapacity'.
247+
worstCaseCapacity ::
248+
Measure.Measure (TxMeasure blk)
249+
=> MempoolCapacity blk
250+
-> TxMeasure blk
251+
worstCaseCapacity capacity =
252+
x
253+
where
254+
MempoolCapacity {
255+
mcBlockCapacity = cap
256+
, mcBlockMultiplicity = mult
257+
} = capacity
258+
259+
InstantiatedAt x =
260+
stimes mult $ InstantiatedAt @Measure.Measure cap
261+
262+
instance NoThunks (TxMeasure blk) => NoThunks (MempoolCapacity blk)
263+
264+
deriving instance Eq (TxMeasure blk) => Eq (MempoolCapacity blk)
265+
deriving instance Show (TxMeasure blk) => Show (MempoolCapacity blk)
213266

214267
{-------------------------------------------------------------------------------
215268
Result of adding a transaction to the mempool

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

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -67,35 +67,30 @@ import Ouroboros.Consensus.Util.IOLike hiding (newMVar)
6767
data InternalState blk = IS {
6868
-- | Transactions currently in the mempool
6969
--
70-
-- NOTE: the total size of the transactions in 'isTxs' may exceed the
71-
-- current capacity ('isCapacity'). When the capacity computed from the
72-
-- ledger has shrunk, we don't remove transactions from the Mempool to
73-
-- satisfy the new lower limit. We let the transactions get removed in
74-
-- the normal way: by becoming invalid w.r.t. the updated ledger state.
75-
-- We treat a Mempool /over/ capacity in the same way as a Mempool /at/
76-
-- capacity.
77-
isTxs :: !(TxSeq (TxMeasure blk) (Validated (GenTx blk)))
70+
-- See the note on 'MempoolCapacity' about the mempool possibly being
71+
-- over-capacity.
72+
isTxs :: !(TxSeq (TxMeasure blk) (Validated (GenTx blk)))
7873

7974
-- | The cached IDs of transactions currently in the mempool.
8075
--
8176
-- This allows one to more quickly lookup transactions by ID from a
8277
-- 'MempoolSnapshot' (see 'snapshotHasTx').
8378
--
8479
-- This should always be in-sync with the transactions in 'isTxs'.
85-
, isTxIds :: !(Set (GenTxId blk))
80+
, isTxIds :: !(Set (GenTxId blk))
8681

8782
-- | The cached ledger state after applying the transactions in the
8883
-- Mempool against the chain's ledger state. New transactions will be
8984
-- validated against this ledger.
9085
--
9186
-- INVARIANT: 'isLedgerState' is the ledger resulting from applying the
9287
-- transactions in 'isTxs' against the ledger identified 'isTip' as tip.
93-
, isLedgerState :: !(TickedLedgerState blk)
88+
, isLedgerState :: !(TickedLedgerState blk)
9489

9590
-- | The tip of the chain that 'isTxs' was validated against
9691
--
9792
-- This comes from the underlying ledger state ('tickedLedgerState')
98-
, isTip :: !(ChainHash blk)
93+
, isTip :: !(ChainHash blk)
9994

10095
-- | The most recent 'SlotNo' that 'isTxs' was validated against
10196
--
@@ -104,27 +99,16 @@ data InternalState blk = IS {
10499
-- slot, see 'tickLedgerState') and 'isSlotNo' will be set to @succ s@,
105100
-- which is different from the slot of the original ledger state, which
106101
-- will remain in 'isTip'.
107-
, isSlotNo :: !SlotNo
102+
, isSlotNo :: !SlotNo
108103

109104
-- | The mempool 'TicketNo' counter.
110105
--
111106
-- See 'vrLastTicketNo' for more information.
112107
, isLastTicketNo :: !TicketNo
113108

114-
-- | The mempool will refuse additional transactions when it already
115-
-- contains enough to _fill_ this many (or more) blocks, each of size up
116-
-- to @isCapacity@.
117-
--
118-
-- There might be a transaction in the Mempool triggering a change in the
119-
-- maximum transaction capacity of a block, which would change the
120-
-- Mempool's capacity. We don't want the Mempool's capacity to depend on
121-
-- its contents. Any changes caused by those txs will take effect after
122-
-- applying the block they end up in.
123-
, isMultiplicity :: !Int
124-
125-
-- | The capacity of a block according to the last ledger state the
126-
-- mempool was synchronized with.
127-
, isCapacity :: !(TxMeasure blk)
109+
-- | The capacity of a block according to the ledger state the mempool
110+
-- was most recently synchronized with.
111+
, isCapacity :: !(MempoolCapacity blk)
128112
}
129113
deriving (Generic)
130114

@@ -159,8 +143,11 @@ initInternalState capacityOverride lastTicketNo cfg slot st = IS {
159143
, isTip = castHash (getTipHash st)
160144
, isSlotNo = slot
161145
, isLastTicketNo = lastTicketNo
162-
, isCapacity = capacityOverride `applyOverrides` blockTxCapacity cfg st
163-
, isMultiplicity = 2
146+
, isCapacity = MempoolCapacity {
147+
mcBlockCapacity =
148+
capacityOverride `applyOverrides` blockTxCapacity cfg st
149+
, mcBlockMultiplicity = 2
150+
}
164151
}
165152

166153
{-------------------------------------------------------------------------------
@@ -199,7 +186,6 @@ data MempoolEnv m blk = MempoolEnv {
199186

200187
initMempoolEnv :: ( IOLike m
201188
, NoThunks (GenTxId blk)
202-
, NoThunks (TxMeasure blk)
203189
, LedgerSupportsMempool blk
204190
, ValidateEnvelope blk
205191
)
@@ -260,10 +246,9 @@ data ValidationResult invalidTx blk = ValidationResult {
260246
-- | The slot number of the (imaginary) block the txs will be placed in
261247
, vrSlotNo :: SlotNo
262248

263-
-- | Capacity of the Mempool. Corresponds to 'vrBeforeTip' and
264-
-- 'vrBeforeSlotNo', /not/ 'vrAfter'.
265-
, vrBeforeCapacity :: TxMeasure blk
266-
, vrMultiplicity :: Int
249+
-- | The capacity of the mempool according to the ledger state of
250+
-- 'vrBeforeTip' and 'vrBeforeSlotNo', /not/ the 'vrAfter' ledger state.
251+
, vrBeforeCapacity :: MempoolCapacity blk
267252

268253
-- | The transactions that were found to be valid (oldest to newest)
269254
, vrValid :: TxSeq (TxMeasure blk) (Validated (GenTx blk))
@@ -382,14 +367,12 @@ internalStateFromVR vr = IS {
382367
, isSlotNo = vrSlotNo
383368
, isLastTicketNo = vrLastTicketNo
384369
, isCapacity = vrBeforeCapacity
385-
, isMultiplicity = vrMultiplicity
386370
}
387371
where
388372
ValidationResult {
389373
vrBeforeTip
390374
, vrSlotNo
391375
, vrBeforeCapacity
392-
, vrMultiplicity
393376
, vrValid
394377
, vrValidTxIds
395378
, vrAfter
@@ -402,7 +385,6 @@ validationResultFromIS is = ValidationResult {
402385
vrBeforeTip = isTip
403386
, vrSlotNo = isSlotNo
404387
, vrBeforeCapacity = isCapacity
405-
, vrMultiplicity = isMultiplicity
406388
, vrValid = isTxs
407389
, vrValidTxIds = isTxIds
408390
, vrNewValid = Nothing
@@ -419,7 +401,6 @@ validationResultFromIS is = ValidationResult {
419401
, isSlotNo
420402
, isLastTicketNo
421403
, isCapacity
422-
, isMultiplicity
423404
} = is
424405

425406
-- | Create a Mempool Snapshot from a given Internal State of the mempool.

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module Ouroboros.Consensus.Mempool.Init (
77
, openMempoolWithoutSyncThread
88
) where
99

10-
import Control.Arrow ((&&&))
1110
import Control.Monad (void)
1211
import Control.Tracer
1312
import Ouroboros.Consensus.Block
@@ -108,7 +107,7 @@ mkMempool mpEnv = Mempool
108107
, syncWithLedger = implSyncWithLedger mpEnv
109108
, getSnapshot = snapshotFromIS <$> readTVar istate
110109
, getSnapshotFor = \fls -> pureGetSnapshotFor cfg fls co <$> readTVar istate
111-
, getCapacity = (isCapacity &&& isMultiplicity) <$> readTVar istate
110+
, getCapacity = isCapacity <$> readTVar istate
112111
}
113112
where MempoolEnv { mpEnvStateVar = istate
114113
, mpEnvAddTxsRemoteFifo = remoteFifo

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pureTryAddTx ::
176176
-- ^ The current internal state of the mempool.
177177
-> TryAddTx blk
178178
pureTryAddTx cfg wti tx is
179-
| willItFit is (txInBlockSize cfg (isLedgerState is) tx)
179+
| shouldTryToAdd is (txInBlockSize cfg (isLedgerState is) tx)
180180
=
181181
case eVtx of
182182
-- We only extended the ValidationResult with a single transaction
@@ -208,20 +208,30 @@ pureTryAddTx cfg wti tx is
208208
(eVtx, vr) = extendVRNew cfg wti tx $ validationResultFromIS is
209209
is' = internalStateFromVR vr
210210

211-
willItFit ::
211+
-- | Should the mempool admit this tx?
212+
--
213+
-- There's a simple rule, but one exception to that rule. Let this transaction
214+
-- in if and only if the resulting mempool would not be over capacity. However,
215+
-- if the tx alone is too big to fit into even a block that contained no other
216+
-- txs, then try to add it to the mempool; it will be immediately recognized as
217+
-- invalid.
218+
shouldTryToAdd ::
212219
Measure (TxMeasure blk)
213220
=> InternalState blk -> TxMeasure blk -> Bool
214-
willItFit is tx
221+
shouldTryToAdd is tx
215222
| not (tx Measure.<= cap) = True -- let it be found invalid
216223
| otherwise =
217-
go (isTxs is) (max 0 $ isMultiplicity is - 1)
224+
go (isTxs is) (max 0 $ mult - 1)
218225
where
219-
cap = isCapacity is
226+
MempoolCapacity {
227+
mcBlockCapacity = cap
228+
, mcBlockMultiplicity = mult
229+
} = isCapacity is
220230

221231
go !txseq = \case
222232
0 -> msSize (TxSeq.toMempoolSize txseq) `Measure.plus` tx Measure.<= cap
223233
n -> case txseq of
224-
TxSeq.Empty -> go txseq 0
234+
TxSeq.Empty -> True -- guard above ensures 0 + tx <= cap
225235
_ -> go (snd $ TxSeq.splitAfterTxSize txseq cap) (n - 1)
226236

227237
{-------------------------------------------------------------------------------

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/MiniProtocol/LocalTxMonitor/Server.hs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
{-# LANGUAGE NamedFieldPuns #-}
22
{-# LANGUAGE ScopedTypeVariables #-}
3-
{-# LANGUAGE TypeApplications #-}
4-
{-# LANGUAGE TypeFamilies #-}
53
{-# LANGUAGE ViewPatterns #-}
64

75
module Ouroboros.Consensus.MiniProtocol.LocalTxMonitor.Server (localTxMonitorServer) where
86

9-
import Data.DerivingVia (InstantiatedAt (..))
10-
import Data.Measure (Measure)
11-
import Data.Semigroup (stimes)
127
import Ouroboros.Consensus.Block
138
import Ouroboros.Consensus.Ledger.SupportsMempool
149
import Ouroboros.Consensus.Mempool
@@ -89,10 +84,8 @@ localTxMonitorServer mempool =
8984
&&
9085
snapshotSlotNo a == snapshotSlotNo b
9186

87+
query :: STM m (TxMeasure blk, MempoolSnapshot blk)
9288
query = do
93-
(capacity, mult) <- getCapacity mempool
89+
capacity <- worstCaseCapacity <$> getCapacity mempool
9490
snapshot <- getSnapshot mempool
95-
let InstantiatedAt capacity' =
96-
stimes mult
97-
$ InstantiatedAt @Measure capacity
98-
pure (capacity', snapshot)
91+
pure (capacity, snapshot)

ouroboros-consensus/test/consensus-test/Test/Consensus/Mempool.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ prop_Mempool_semigroup_removeTxs (TestSetupWithTxsInMempool testSetup txsToRemov
214214
prop_Mempool_getCapacity :: MempoolCapTestSetup -> Property
215215
prop_Mempool_getCapacity mcts =
216216
withTestMempool testSetup $ \TestMempool{mempool} -> do
217-
(actualCapacity, _mult) <- atomically $ getCapacity mempool
218-
pure (actualCapacity === min testCapacity simpleBlockTxCapacity )
217+
actualCapacity <- atomically $ worstCaseCapacity <$> getCapacity mempool
218+
pure (actualCapacity === 2 * min testCapacity simpleBlockTxCapacity )
219219
where
220220
Just testCapacity = testMempoolCapOverride testSetup
221221
MempoolCapTestSetup (TestSetupWithTxs testSetup _txsToAdd) = mcts

0 commit comments

Comments
 (0)