@@ -52,7 +52,7 @@ import Ouroboros.Consensus.Storage.Common
5252import Ouroboros.Consensus.Storage.ImmutableDB.Chunks as ImmutableDB
5353import Ouroboros.Consensus.Util.IOLike
5454import qualified Ouroboros.Network.AnchoredFragment as AF
55- import Ouroboros.Network.Block (ChainUpdate (.. ), Point , blockPoint )
55+ import Ouroboros.Network.Block (ChainUpdate (.. ), Point , blockPoint , genesisPoint )
5656import qualified Ouroboros.Network.Mock.Chain as Mock
5757import Test.Ouroboros.Storage.ChainDB.Model (Model )
5858import qualified Test.Ouroboros.Storage.ChainDB.Model as Model
@@ -116,6 +116,15 @@ tests =
116116 " Empty slot, returns block at next filled slot"
117117 [testCase " system" $ runSystemIO waitForImmutableBlock_emptySlot]
118118 ]
119+ , testGroup
120+ " Interaction of ImmutableDB, wiping the VolatileDB and ledger state snapshots"
121+ [ testGroup
122+ " Chain not long enough to take a snapshot, so blocks are not persisted into ImmutableDB and are lost."
123+ [testCase " system" $ runSystemIO updateLedgerSnapshots_WipeVolatileDB_withoutSnapshot]
124+ , testGroup
125+ " Chain is long enough to take a snapshot, blocks are copied into ImmutableDB."
126+ [testCase " system" $ runSystemIO updateLedgerSnapshots_WipeVolatileDB_withSnapshot]
127+ ]
119128 ]
120129
121130followerInstructionOnEmptyChain :: (SupportsUnitTest m , MonadError TestFailure m ) => m ()
@@ -329,6 +338,63 @@ waitForImmutableBlock_emptySlot = do
329338 where
330339 fork0 = TestBody 0 True Nothing
331340
341+ -- | Taking a ledger state snapshot should only copy blocks to the
342+ -- ImmutableDB when the snapshot policy selects slots for snapshotting. When the
343+ -- immutable chain is too short, no blocks should be flushed, and WipeVolatileDB
344+ -- should recover to the tip of the (empty) ImmutableDB.
345+ --
346+ -- See 'updateLedgerSnapshots_WipeVolatileDB_withSnapshot' for the scenario where
347+ -- the snapshot is taken.
348+ updateLedgerSnapshots_WipeVolatileDB_withoutSnapshot ::
349+ forall m .
350+ ( Block m ~ TestBlock
351+ , SupportsUnitTest m
352+ , MonadError TestFailure m
353+ ) =>
354+ m ()
355+ updateLedgerSnapshots_WipeVolatileDB_withoutSnapshot = do
356+ b1 <- addBlock $ firstBlock 1 $ fork0
357+ b2 <- addBlock $ mkNextBlock b1 3 $ fork0
358+ _b3 <- addBlock $ mkNextBlock b2 5 $ fork0
359+
360+ -- With k=2, 3 blocks are not enough to trigger a snapshot,
361+ updateLedgerSnapshots
362+
363+ tip <- wipeVolatileDB
364+ tip
365+ == genesisPoint
366+ `orFailWith` (" Expected ChainDB tip after wiping VolatileDB to be at Genesis, but got: " <> show tip)
367+ where
368+ fork0 = TestBody 1 True Nothing
369+
370+ -- | See 'updateLedgerSnapshots_WipeVolatileDB_withoutSnapshot' for details.
371+ updateLedgerSnapshots_WipeVolatileDB_withSnapshot ::
372+ forall m .
373+ ( Block m ~ TestBlock
374+ , SupportsUnitTest m
375+ , MonadError TestFailure m
376+ ) =>
377+ m ()
378+ updateLedgerSnapshots_WipeVolatileDB_withSnapshot = do
379+ b1 <- addBlock $ firstBlock 1 $ fork0
380+ b2 <- addBlock $ mkNextBlock b1 3 $ fork0
381+ b3 <- addBlock $ mkNextBlock b2 5 $ fork0
382+ b4 <- addBlock $ mkNextBlock b3 7 $ fork0
383+ _ <- addBlock $ mkNextBlock b4 9 $ fork0
384+
385+ updateLedgerSnapshots
386+
387+ tip <- wipeVolatileDB
388+ tip
389+ /= genesisPoint
390+ `orFailWith` (" Expected ChainDB non-Origin tip after wiping VolatileDB, got: " <> show tip)
391+ where
392+ fork0 = TestBody 1 True Nothing
393+
394+ {- ------------------------------------------------------------------------------
395+ Helpers and testing infrastructure
396+ -------------------------------------------------------------------------------}
397+
332398streamAssertSuccess ::
333399 (MonadError TestFailure m , SupportsUnitTest m , Mock. HasHeader (Block m )) =>
334400 StreamFrom (Block m ) -> StreamTo (Block m ) -> m (IteratorId m )
@@ -444,6 +510,10 @@ class SupportsUnitTest m where
444510 IteratorId m ->
445511 m (API. IteratorResult (Block m ) (AllComponents (Block m )))
446512
513+ updateLedgerSnapshots :: m ()
514+
515+ wipeVolatileDB :: m (Point (Block m ))
516+
447517 waitForImmutableBlock ::
448518 RealPoint (Block m ) -> m (Either API. SeekBlockError (RealPoint (Block m )))
449519
@@ -522,6 +592,15 @@ instance
522592 persistBlksThenGC =
523593 void $ runModelCmd SM. PersistBlksThenGC
524594
595+ updateLedgerSnapshots =
596+ void $ runModelCmd SM. UpdateLedgerSnapshots
597+
598+ wipeVolatileDB = do
599+ result <- runModelCmd SM. WipeVolatileDB
600+ case result of
601+ SM. Point p -> pure p
602+ _ -> error $ " wipeVolatileDB: unexpected result" <> show result
603+
525604 stream from to = do
526605 result <- runModelCmd (SM. Stream from to)
527606 case result of
@@ -656,6 +735,15 @@ instance (IOLike m, TestConstraints blk) => SupportsUnitTest (SystemM blk m) whe
656735 persistBlksThenGC =
657736 void $ runCmd SM. PersistBlksThenGC
658737
738+ updateLedgerSnapshots = do
739+ void $ runCmd SM. UpdateLedgerSnapshots
740+
741+ wipeVolatileDB = do
742+ result <- runCmd SM. WipeVolatileDB
743+ case result of
744+ SM. Point p -> pure p
745+ _ -> error $ " wipeVolatileDB: unexpected result"
746+
659747 newFollower = do
660748 result <- runCmd (SM. NewFollower API. SelectedChain )
661749 case result of
0 commit comments