Skip to content

Commit 167d5fc

Browse files
committed
simulation: fix issue with IBs getting dropped before validation
1 parent b9fd163 commit 167d5fc

File tree

3 files changed

+67
-23
lines changed

3 files changed

+67
-23
lines changed

simulation/src/LeiosProtocol/Short/Node.hs

+44-21
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ data LeiosNodeEvent
7777
= PraosNodeEvent !(PraosNode.PraosNodeEvent RankingBlockBody)
7878
| LeiosNodeEventCPU !CPUTask
7979
| LeiosNodeEvent !BlockEvent !LeiosEventBlock
80+
| LeiosNodeEventLedgerState !RankingBlockId
8081
deriving (Show)
8182

8283
--------------------------------------------------------------
@@ -512,8 +513,8 @@ pruneExpiredUnadoptedEBs tracer LeiosNodeConfig{leios, slotConfig} st = go (toEn
512513
-- Prune st.relayEBState.relayBufferVar for *certified* EBs in the current pipeline
513514
-- which were not adopted as part of the chain, and return the set of pruned EBs:
514515
ebsPruned <-
515-
fmap (fmap snd . RB.values) . stateTVar st.relayEBState.relayBufferVar $
516-
RB.partition $ \ebEntry -> do
516+
(fmap . fmap) snd . partitionRBVar st.relayEBState.relayBufferVar $
517+
\ebEntry -> do
517518
let ebId = (snd ebEntry.value).id
518519
let ebSlot = (fst ebEntry.value).slot
519520
let ebInPipeline = ebSlot `inRange` ebRange
@@ -559,8 +560,8 @@ pruneExpiredUncertifiedEBs tracer LeiosNodeConfig{leios, slotConfig} st = go (to
559560
atomically $ do
560561
votesForEB <- readTVar st.votesForEBVar
561562
-- Prune st.relayEBState.relayBufferVar for EBs in pipeline p that did not become certified.
562-
ebsPruned <-
563-
fmap (fmap snd . RB.values) . stateTVar st.relayEBState.relayBufferVar . RB.partition $ \ebEntry -> do
563+
ebsPruned <- (fmap . fmap) snd . partitionRBVar st.relayEBState.relayBufferVar $
564+
\ebEntry -> do
564565
let ebId = (fst ebEntry.value).id
565566
let ebSlot = (fst ebEntry.value).slot
566567
let ebAlreadyVotedOn = ebSlot < pruneTo
@@ -591,20 +592,22 @@ pruneExpiredVotes ::
591592
LeiosNodeConfig ->
592593
LeiosNodeState m ->
593594
m ()
594-
pruneExpiredVotes _tracer LeiosNodeConfig{leios = leios@LeiosConfig{pipeline = _ :: SingPipeline p}, slotConfig} st = go (toEnum 0)
595+
pruneExpiredVotes tracer LeiosNodeConfig{leios = leios@LeiosConfig{pipeline = _ :: SingPipeline p}, slotConfig} st = go (toEnum 0)
595596
where
596597
go p = do
597598
let pruneIBDeliveryTo = succ $ snd (stageRangeOf @p leios p Short.Propose)
598599
let pruneTo = succ (lastVoteSend leios p)
599600
_ <- waitNextSlot slotConfig (succ (lastVoteRecv leios p))
600-
atomically $ do
601-
modifyTVar' st.relayVoteState.relayBufferVar $
602-
RB.filter $ \voteEntry ->
603-
let voteSlot = (snd voteEntry.value).slot
604-
in voteSlot >= pruneTo
601+
votesPruned <- atomically $ do
605602
writeTVar st.prunedVoteStateToVar $! pruneTo
606603
-- delivery times for IBs are only needed to vote, so they can be pruned too.
607604
modifyTVar' st.ibDeliveryTimesVar $ Map.filter $ \(slot, _) -> slot >= pruneIBDeliveryTo
605+
partitionRBVar st.relayVoteState.relayBufferVar $
606+
\voteEntry ->
607+
let voteSlot = (snd voteEntry.value).slot
608+
in voteSlot < pruneTo
609+
for_ votesPruned $ \vt -> do
610+
traceWith tracer $ LeiosNodeEvent Pruned (EventVote $ snd vt)
608611
go (succ p)
609612

610613
computeLedgerStateThread ::
@@ -614,8 +617,8 @@ computeLedgerStateThread ::
614617
LeiosNodeConfig ->
615618
LeiosNodeState m ->
616619
m ()
617-
computeLedgerStateThread _tracer _cfg st = forever $ do
618-
_readyLedgerState <- atomically $ do
620+
computeLedgerStateThread tracer _cfg st = forever $ do
621+
readyLedgerState <- atomically $ do
619622
-- TODO: this will get more costly as the base chain grows,
620623
-- however it grows much more slowly than anything else.
621624
blocks <- readTVar st.praosState.blockFetchControllerState.blocksVar
@@ -639,7 +642,8 @@ computeLedgerStateThread _tracer _cfg st = forever $ do
639642
when (null readyLedgerState) retry
640643
modifyTVar' st.ledgerStateVar (`Map.union` Map.fromList readyLedgerState)
641644
return readyLedgerState
642-
-- TODO? trace readyLedgerState
645+
for_ readyLedgerState $ \(rb, _) -> do
646+
traceWith tracer (LeiosNodeEventLedgerState rb)
643647
return ()
644648

645649
adoptIB :: MonadSTM m => LeiosNodeState m -> InputBlock -> UTCTime -> STM m ()
@@ -720,19 +724,19 @@ dispatchValidation tracer cfg leiosState req =
720724
then leiosState.waitingForRBVar
721725
-- TODO: assumes payload can be validated without content of EB, check with spec.
722726
else leiosState.waitingForLedgerStateVar
723-
modifyTVar' var $ Map.insertWith (++) prev [queue [task]]
727+
waitFor var [(prev, [queue [task]])]
724728
return []
725729
ValidateIBS ibs deliveryTime completion -> do
726730
-- NOTE: IBs with an RB reference have to wait for ledger state of that RB.
727731
let waitingLedgerState =
728-
Map.fromListWith
729-
(++)
730-
[ (rbHash, [queue [valIB ib deliveryTime completion]])
731-
| ib <- ibs
732-
, BlockHash rbHash <- [(fst ib).rankingBlock]
733-
]
732+
[ (rbHash, [queue [valIB ib deliveryTime completion]])
733+
| ib <- ibs
734+
, BlockHash rbHash <- [(fst ib).rankingBlock]
735+
]
734736

735-
modifyTVar' leiosState.waitingForLedgerStateVar (`Map.union` waitingLedgerState)
737+
waitFor
738+
leiosState.waitingForLedgerStateVar
739+
waitingLedgerState
736740

737741
return [valIB ib deliveryTime completion | ib@(h, _) <- ibs, GenesisHash <- [h.rankingBlock]]
738742
ValidateEBS ebs completion -> do
@@ -894,3 +898,22 @@ mkSchedule cfg = do
894898
pickFromRanges rng0 rs = snd $ mapAccumL f rng0 rs
895899
where
896900
f rng r = coerce $ swap $ uniformR (coerce r :: (Word64, Word64)) rng
901+
902+
-- * Utils
903+
904+
partitionRBVar ::
905+
(Ord key, MonadSTM m) =>
906+
TVar m (RB.RelayBuffer key value) ->
907+
(RB.EntryWithTicket key value -> Bool) ->
908+
STM m [value]
909+
partitionRBVar var f = fmap RB.values . stateTVar' var $ RB.partition f
910+
911+
waitFor ::
912+
MonadSTM m =>
913+
TVar m (Map RankingBlockId [STM m ()]) ->
914+
[(RankingBlockId, [STM m ()])] ->
915+
STM m ()
916+
waitFor var xs = do
917+
modifyTVar'
918+
var
919+
(flip (Map.unionWith (++)) $ Map.fromListWith (++) xs)

simulation/src/LeiosProtocol/Short/Sim.hs

+18-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ module LeiosProtocol.Short.Sim where
2020

2121
import Chan
2222
import Control.Exception (assert)
23-
import Control.Monad (forever)
23+
import Control.Monad (forever, guard)
2424
import Control.Monad.Class.MonadFork (MonadFork (forkIO))
2525
import Control.Monad.IOSim as IOSim (IOSim, runSimTrace)
2626
import Control.Tracer as Tracer (
@@ -49,6 +49,7 @@ import LeiosProtocol.Short.Node
4949
import ModelTCP
5050
import Network.TypedProtocol
5151
import PraosProtocol.BlockFetch (Message (..))
52+
import qualified PraosProtocol.Common.Chain as Chain
5253
import PraosProtocol.PraosNode (PraosMessage (..), praosMessageLabel)
5354
import SimTCPLinks
5455
import SimTypes
@@ -110,6 +111,14 @@ logLeiosEvent nodeNames loudness e = case e of
110111
GenesisHash -> "genesis"
111112
BlockHash x -> show (coerce x :: Int)
112113
logNode nid (PraosNodeEvent x) = logPraos nid x
114+
logNode nid (LeiosNodeEventLedgerState rbId) = do
115+
guard emitDebug
116+
Just $
117+
mconcat
118+
[ "tag" .= asString "ledgerstate"
119+
, node nid
120+
, "id" .= show (coerce rbId :: Int)
121+
]
113122
logNode nid (LeiosNodeEventCPU CPUTask{..}) =
114123
Just $
115124
mconcat
@@ -176,7 +185,14 @@ logLeiosEvent nodeNames loudness e = case e of
176185
Just $
177186
mconcat
178187
[cpuTag, node nid, "task" .= task]
179-
logPraos _ (PraosNodeEventNewTip _chain) = Nothing
188+
logPraos nid (PraosNodeEventNewTip chain) = do
189+
guard emitDebug
190+
Just $
191+
mconcat
192+
[ "tag" .= asString "chaintip"
193+
, "id" .= rbRef (Chain.headHash chain)
194+
, node nid
195+
]
180196
logMsg :: LeiosMessage -> Maybe Series
181197
logMsg (RelayIB msg) = (ibKind <>) <$> logRelay (.id) msg
182198
logMsg (RelayEB msg) = (ebKind <>) <$> logRelay (.id) msg

simulation/src/STMCompat.hs

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE BangPatterns #-}
12
{-# LANGUAGE NamedFieldPuns #-}
23
{-# LANGUAGE ScopedTypeVariables #-}
34

@@ -11,6 +12,7 @@ module STMCompat (
1112
asTakeOnly,
1213
takeTakeOnlyTMVar,
1314
tryTakeTakeOnlyTMVar,
15+
stateTVar',
1416
) where
1517

1618
import Control.Concurrent.Class.MonadSTM (MonadSTM (..))
@@ -41,3 +43,6 @@ takeTakeOnlyTMVar TakeOnly{unTakeOnly} = takeTMVar unTakeOnly
4143

4244
tryTakeTakeOnlyTMVar :: MonadSTM m => TakeOnly (TMVar m a) -> STM m (Maybe a)
4345
tryTakeTakeOnlyTMVar TakeOnly{unTakeOnly} = tryTakeTMVar unTakeOnly
46+
47+
stateTVar' :: MonadSTM m => TVar m t -> (t -> (a, t)) -> STM m a
48+
stateTVar' var f = stateTVar var (\x -> let (!a, !b) = f x in (a, b))

0 commit comments

Comments
 (0)