Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
62113b8
LeiosTxCache: best-effort prevention of spurious inserts into missing…
nfrisby Aug 10, 2026
02c8285
LeiosTxCache: best-effort prevention of spurious inserts into missing…
nfrisby Aug 10, 2026
21872eb
LeiosTxCache: remove stale warning comment
nfrisby Aug 10, 2026
ebaeb5a
NodeKernel.Forge: improve formal parameter name
nfrisby Aug 10, 2026
d414467
LeiosFetch: remove filterMissingWork and acquiredEbBodies
nfrisby Aug 10, 2026
85b4331
LeiosTxCache: fuse lookupTx into insertBody
nfrisby Aug 10, 2026
fe727a3
LeiosFetch: mitigate EbBodies with duplicate TxHashes
nfrisby Aug 10, 2026
088b800
LeiosFetch: TODOs for prioritization gap due to LeiosTxCache lookupBo…
nfrisby Aug 11, 2026
ab8a4e1
LeiosFetch: add regression tests for bug masked by filterMissingWork
nfrisby Aug 11, 2026
aef747f
LeiosFetch: only emit MsgLeiosBlockTxsRequest with a real LeiosPoint
nfrisby Aug 11, 2026
f13afce
LeiosFetch: bugfix, remove arrived tx from missingEbTxs _entirely_
nfrisby Aug 11, 2026
934a0ed
LeiosFetch: intro FetchArrivalBytes tracers, refactor as needed
nfrisby Aug 12, 2026
fe86f9b
LeiosFetch: make unit test more flexible
nfrisby Aug 12, 2026
a677bd3
LeiosFetch: reintroduce acquiredEbBodies instead of using LeiosTxCache
nfrisby Aug 13, 2026
75236e9
LeiosFetch: regression test, don't request EB bodies we already have
nfrisby Aug 13, 2026
f7f6c61
LeiosFetch: the deletion in msgLeiosBlock needs reverseSlotIndexByEbHash
nfrisby Aug 13, 2026
6e7c59f
LeiosFetch: reintroduce the locking bug to prove regression test
nfrisby Aug 13, 2026
b42488a
Revert "LeiosFetch: reintroduce the locking bug to prove regression t…
nfrisby Aug 13, 2026
b26c769
LeiosFetch & Forge: merge the announcement/body/closure handlers
nfrisby Aug 13, 2026
e1bba10
LeiosFetch.Invariants: 10x tests and some coverage indicators
nfrisby Aug 13, 2026
481629b
DONOTMERGE reduce fetch multiplicity to 1, for more obvious Grafana m…
nfrisby Aug 11, 2026
2d7c06c
LeiosFetch: bugfix in EB announcement/body-arrival tracking
nfrisby Aug 14, 2026
536b889
LeiosFetch: delete blockingPerEb from LeiosOutstanding
nfrisby Aug 18, 2026
91aba2c
WIP delete EbTxs fields of LeiosOutstanding
nfrisby Aug 18, 2026
a8e0997
WIP have Claude disable EbTxs fetch logic tests
nfrisby Aug 18, 2026
7154283
LeiosFetch: add LeiosDemoTypes.LeiosJobs module
nfrisby Aug 18, 2026
0bfc9d0
LeiosFetch: initialize LeiosJobs on EB body arrival
nfrisby Aug 18, 2026
fe625c8
LeiosFetch: accelerate LeiosJobs prune on peer disconnect
nfrisby Aug 18, 2026
762af06
LeiosFetch: beginning of major rewrite
nfrisby Aug 24, 2026
694cf9e
LeiosFetch: retain root hash per job instead of EB body
nfrisby Aug 24, 2026
8e28006
LeiosFetch: bugfix, avoid multiple AcquiredEbTxs notifications
nfrisby Aug 24, 2026
c162ce6
LeiosFetch: fetch aggressively from BigLedgerPeers
nfrisby Aug 24, 2026
10d03aa
LeiosFetch: remove now-dead maxRequestsPerEb and maxRequestsPerTx
nfrisby Aug 24, 2026
74c118e
LeiosFetch: check Mempool between checking LeiosTxCache and issuing L…
nfrisby Aug 25, 2026
a387852
Mempool: avoid recalculating the Leios TxHashes
nfrisby Aug 25, 2026
bd309f7
LeiosFetch: two-tiered EB prioritization
nfrisby Aug 25, 2026
090ff7a
LeiosFetch: improve some comments
nfrisby Aug 25, 2026
54d1857
LeiosFetch: remove unsafe degree of freedom in config
nfrisby Aug 25, 2026
d4912da
LeiosFetch: performance bugfix, warm-up the initial ebState somewhat
nfrisby Aug 25, 2026
e595d56
LeiosFetch: add TraceLeiosFetchDecision, LeiosFetch decision iteratio…
nfrisby Aug 25, 2026
cac4608
LeiosFetch: replace TraceLeiosTxCacheEbBody by TraceLeiosBodyHits
nfrisby Aug 25, 2026
06013c7
LeiosTxCache: rename InsertBodySummary to LeiosTxCacheInsertBodySummary
nfrisby Aug 25, 2026
73be98b
LeiosTxCache: correct a false comment
nfrisby Aug 25, 2026
7972c17
FIXUP stop defaulting leiosTx{Bytes,Hash}OfGenTx methods
nfrisby Aug 25, 2026
831a3c0
LeiosFetch: add age metrics to TraceLeiosBlock{,Txs}Acquired
nfrisby Aug 25, 2026
4e0146f
LeiosFetch: fix the test suites for the age arguments
ch1bo Aug 28, 2026
c11d1c4
Apply fourmolu and cabal-gild
ch1bo Aug 28, 2026
df7d228
LeiosFetch: choose random JobId instead of minimum
nfrisby Aug 26, 2026
07fae70
LioesTxCache & Forge: remove unused LANGUAGE pragmas
nfrisby Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,14 @@ instance
(leiosClosureTxKeySets inner)
_ -> emptyLedgerTables

leiosTxHashOfGenTx tx = case tx of
GenTxDijkstra inner -> leiosTxHashOfGenTx inner
_ -> Nothing

leiosTxBytesOfGenTx tx = case tx of
GenTxDijkstra inner -> leiosTxBytesOfGenTx inner
_ -> Nothing

-----

-- | We don't want to add the ResolveLeiosBlock sin-bin to SingleEraBlock, so we
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

module Ouroboros.Consensus.Shelley.Ledger.Leios () where

import Cardano.Binary (serialize')
import qualified Cardano.Crypto.Hash as Crypto (hashToBytesShort)
import Cardano.Ledger.Api (Tx)
import Cardano.Ledger.Binary (decCBOR, decodeFullAnnotator)
Expand Down Expand Up @@ -38,7 +39,9 @@ import LeiosDemoLogic.Announcements.ElBimap (ElId (MkElId))
import LeiosDemoTypes
( EbAnnouncement (..)
, LeiosPoint (..)
, LeiosTx (..)
, RbHash (..)
, hashLeiosTx
)
import Lens.Micro ((.~), (^.))
import Ouroboros.Consensus.Block (ChainHash (..), blockPrevHash, toRawHash)
Expand Down Expand Up @@ -107,6 +110,13 @@ instance
(PraosCrypto c, ShelleyCompatible (Praos c) DijkstraEra) =>
ResolveLeiosBlock (ShelleyBlock (Praos c) DijkstraEra)
where
-- The on-wire bytes and 'TxHash' a forged EB records for each tx (see
-- 'forgeLeiosEb'): 'serialize'' the tx, and hash exactly those bytes. Matching
-- this encoding is what lets the mempool key its txs by the same 'TxHash' an EB
-- lists, so the body-arrival mempool pull can find them.
leiosTxBytesOfGenTx (ShelleyTx _ tx) = Just (serialize' tx)
leiosTxHashOfGenTx (ShelleyTx _ tx) = Just (hashLeiosTx (MkLeiosTx (serialize' tx)))

resolveLeiosClosure leiosDb ebHash = do
mAnnouncedEb <-
leiosDbLookupEbClosure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ prop_leios seed =
_ -> Nothing

acquiredPoints = Set.fromList . flip mapMaybe leiosTraces $ \case
TraceLeiosBlockTxsAcquired point -> Just point
TraceLeiosBlockTxsAcquired point _age -> Just point
_ -> Nothing

-- An EB forged at slot @s@ is required to diffuse iff it has at least
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import Data.Functor ((<&>))
import Data.Hashable (Hashable)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe.Strict (StrictMaybe (SJust))
import qualified Data.Primitive.MutVar as Prim
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
Expand Down Expand Up @@ -144,6 +145,7 @@ import Ouroboros.Consensus.Config (DiffusionPipeliningSupport (..))
import Ouroboros.Consensus.HeaderValidation (HeaderWithTime)
import Ouroboros.Consensus.Ledger.SupportsMempool
import Ouroboros.Consensus.Ledger.SupportsProtocol
import Ouroboros.Consensus.Mempool.API (getLeiosTxIndex)
import Ouroboros.Consensus.MiniProtocol.BlockFetch.Server
import Ouroboros.Consensus.MiniProtocol.ChainSync.Client
( ChainSyncStateView (..)
Expand All @@ -159,6 +161,7 @@ import Ouroboros.Consensus.NodeKernel
import qualified Ouroboros.Consensus.Storage.ChainDB.API as ChainDB
import Ouroboros.Consensus.Storage.LedgerDB.Forker
( ResolveLeiosBlock
, leiosTxBytesOfGenTx
)
import Ouroboros.Consensus.Storage.Serialisation (SerialisedHeader)
import Ouroboros.Consensus.Util (ShowProxy, whenJust)
Expand Down Expand Up @@ -423,6 +426,7 @@ mkHandlers
(Just peer)
Leios.ReceivedViaChainSync
Announcements.DoRelay
(SJust hdrSlotTime)
(Just (diffRelTime now hdrSlotTime))
ancHdr
}
Expand Down Expand Up @@ -519,7 +523,7 @@ mkHandlers
(Leios.ancHeader ancH)
)
-- central part of the processing
( \ancHdr (shouldRelay, age, (p, _sz)) -> do
( \ancHdr (shouldRelay, onset, age, (p, _sz)) -> do
traceWith tracer $
MkTraceLeiosPeer $
"MsgLeiosBlockAnnouncement new: " <> Leios.prettyLeiosPoint p
Expand All @@ -531,6 +535,7 @@ mkHandlers
(Just peer)
Leios.ReceivedViaLeiosNotify
shouldRelay
(SJust onset)
(Just age)
ancHdr
)
Expand All @@ -544,43 +549,17 @@ mkHandlers
Prim.writeMutVar peerStateVar (latestPruneSlot', peerSt2)
MsgLeiosBlockOffer point ebBytesSize -> do
traceWith tracer $ MkTraceLeiosPeer $ "MsgLeiosBlockOffer " <> Leios.prettyLeiosPoint point
let MkLeiosPoint{pointEbHash = ebHash} = point
-- TODO: EB announcements now record the authoritative
-- (forger-signed) size via 'recordAnnouncedEb', but this
-- offer handler is not integrated with them yet: it still
-- builds fetch state directly from peer offers, whose sizes
-- are not authoritative (the authoritative one lives in
-- 'headerLeiosAnnouncement' on the parent RB header). Until
-- the two are reconciled, the sanitisation below is the best
-- we can do against malformed offers: drop a zero-sized
-- offer outright (no honest forger ever announces a 0-byte
-- EB) and refuse to overwrite an existing entry that shares
-- the same content hash, so the first-seen (slot, size)
-- wins. The per-peer 'offerings' below is still updated so
-- the peer remains a valid serving candidate.
MVar.modifyMVar_ getLeiosOutstanding $ \outstanding ->
pure $
if ebBytesSize == 0
|| Set.member ebHash (Leios.acquiredEbBodies outstanding)
|| any
((== ebHash) . pointEbHash)
(Map.keys (Leios.missingEbBodies outstanding))
then outstanding
else
outstanding
{ Leios.missingEbBodies =
Map.insert point ebBytesSize (Leios.missingEbBodies outstanding)
}
MVar.modifyMVar_ (Leios.offerings peerVars) $ \(offers1, offers2) -> do
let !offers1' = Set.insert ebHash offers1
pure (offers1', offers2)
void $ MVar.tryPutMVar getLeiosReady ()
-- TODO punish peer for a too-old offer, modulo clock/immtip skew.
Leios.recordEbBodyOffer
(getLeiosOutstanding, getLeiosReady)
peerVars
Leios.TxsClosureNotAlsoOffered
(point, ebBytesSize)
MsgLeiosBlockTxsOffer p -> do
traceWith tracer $ MkTraceLeiosPeer $ "MsgLeiosBlockTxsOffer " <> Leios.prettyLeiosPoint p
let MkLeiosPoint{pointEbHash = ebHash} = p
MVar.modifyMVar_ (Leios.offerings peerVars) $ \(offers1, offers2) -> do
let !offers2' = Set.insert ebHash offers2
pure (offers1, offers2')
-- A closure offer implies the body too.
MVar.modifyMVar_ (Leios.offerings peerVars) $
pure . Map.insertWith Leios.mergeOffer p Leios.TxsClosureAlsoOffered
void $ MVar.tryPutMVar getLeiosReady ()
MsgLeiosVotes vs -> do
traceWith tracer $ MkTraceLeiosPeer $ "MsgLeiosVotes " <> show vs
Expand Down Expand Up @@ -691,6 +670,11 @@ mkHandlers
(getLeiosOutstanding, getLeiosReady)
getLeiosTxCache
leiosConn
systemTime
( Leios.mkMempoolPull
(atomically (getLeiosTxIndex getMempool))
(leiosTxBytesOfGenTx . txForgetValidated)
)
(Leios.MkPeerId peer)
reqVar
responseQ
Expand Down Expand Up @@ -1130,7 +1114,7 @@ mkApps kernel rng Tracers{tTxLogicTracer = _, ..} mkCodecs ByteLimits{..} chainS
csjConfig
getDiffusionPipeliningSupport
$ \csState ->
bracketLeiosPeer them $ \peerVars -> do
bracketLeiosPeer them isBigLedgerPeer $ \peerVars -> do
(r, trailing) <-
runPipelinedPeerWithLimitsRnd
(contramap (TraceLabelPeer them) tChainSyncTracer)
Expand Down Expand Up @@ -1399,17 +1383,18 @@ mkApps kernel rng Tracers{tTxLogicTracer = _, ..} mkCodecs ByteLimits{..} chainS
-- teardown has refunded it.
bracketLeiosPeer ::
ConnectionId addrNTN ->
IsBigLedgerPeer ->
(Leios.LeiosPeerVars m -> m a) ->
m a
bracketLeiosPeer them =
bracketLeiosPeer them isBigLedgerPeer =
bracket
-- Get-or-create: any peer-vars mini-protocol can be the first to run and
-- allocate; the others share the existing vars. No ref count: a hot peer's
-- mini-protocols tear down together, so whichever exits first runs the full
-- cleanup below, and the rest find it already gone (idempotent). A straggler
-- that allocated its own entry cleans that up on its own exit.
( do
fresh <- Leios.newLeiosPeerVars
fresh <- Leios.newLeiosPeerVars isBigLedgerPeer
atomically $ do
peersVars <- LazySTM.readTVar (getLeiosPeersVars kernel)
case Map.lookup pid peersVars of
Expand All @@ -1436,10 +1421,11 @@ mkApps kernel rng Tracers{tTxLogicTracer = _, ..} mkCodecs ByteLimits{..} chainS
ExpandedInitiatorContext
{ eicConnectionId = them
, eicControlMessage = controlMessageSTM
, eicIsBigLedgerPeer = isBigLedgerPeer
}
channel = do
labelThisThread "LeiosNotifyClient"
bracketLeiosPeer them $ \peerVars -> do
bracketLeiosPeer them isBigLedgerPeer $ \peerVars -> do
((), trailing) <-
runPipelinedPeerWithLimits
(TraceLabelPeer them `contramap` tLeiosNotifyTracer)
Expand Down Expand Up @@ -1480,10 +1466,11 @@ mkApps kernel rng Tracers{tTxLogicTracer = _, ..} mkCodecs ByteLimits{..} chainS
ExpandedInitiatorContext
{ eicConnectionId = them
, eicControlMessage = controlMessageSTM
, eicIsBigLedgerPeer = isBigLedgerPeer
}
channel = do
labelThisThread "LeiosFetchClient"
bracketLeiosPeer them $ \peerVars ->
bracketLeiosPeer them isBigLedgerPeer $ \peerVars ->
withLeiosDb leiosDB $ \leiosConn -> do
((), trailing) <-
runPipelinedPeerWithLimits
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,8 @@ mkNodeKernelArgs
leiosTxCache =
do
let (kaRng, rng') = splitGen rng
(psRng, _) = splitGen rng'
(psRng, rng'') = splitGen rng'
(lfRng, _) = splitGen rng''
return
NodeKernelArgs
{ tracers
Expand Down Expand Up @@ -997,6 +998,7 @@ mkNodeKernelArgs
, txSubmissionInitDelay
, leiosDB
, leiosTxCache
, leiosFetchRng = lfRng
}

-- | We allow the user running the node to customise the 'NodeKernelArgs'
Expand Down
Loading
Loading