Skip to content

Commit b168f55

Browse files
committed
Fix rollback tests hanging and block hash identity issues
1 parent 0d8f05a commit b168f55

File tree

6 files changed

+75
-9
lines changed

6 files changed

+75
-9
lines changed

cardano-chain-gen/src/Cardano/Mock/ChainSync/Server.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,8 +369,10 @@ chainSyncServer state codec _blockVersion =
369369
atomically $ do
370370
cps <- readTVar state
371371
let chain = chainDB cps
372+
chainTip = headTip chain
372373
case findFirstPoint (map castPoint points) chain of
373-
Nothing -> pure (Nothing, castTip (headTip chain))
374+
Nothing ->
375+
pure (Nothing, castTip chainTip)
374376
Just ipoint -> do
375377
let !cps' = updateFollower rid ipoint cps
376378
writeTVar state cps'

cardano-chain-gen/test/Test/Cardano/Db/Mock/Config.hs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ module Test.Cardano.Db.Mock.Config (
5757
withFullConfig,
5858
withFullConfigDropDB,
5959
withFullConfigDropDBLog,
60+
withFullConfigDropDBNoFingerprint,
6061
withFullConfigLog,
6162
withCustomConfigDropDBLog,
6263
withCustomConfig,
@@ -470,6 +471,27 @@ withFullConfigDropDBLog =
470471
initCommandLineArgs
471472
Nothing
472473

474+
-- For tests that rollback and restart, fingerprints create divergent chains
475+
withFullConfigDropDBNoFingerprint ::
476+
-- | config filepath
477+
FilePath ->
478+
-- | test label
479+
FilePath ->
480+
(Interpreter -> ServerHandle IO CardanoBlock -> DBSyncEnv -> IO a) ->
481+
IOManager ->
482+
[(Text, Text)] ->
483+
IO a
484+
withFullConfigDropDBNoFingerprint =
485+
withFullConfig'
486+
( WithConfigArgs
487+
{ hasFingerprint = False
488+
, shouldLog = False
489+
, shouldDropDB = True
490+
}
491+
)
492+
initCommandLineArgs
493+
Nothing
494+
473495
withFullConfigLog ::
474496
-- | config filepath
475497
FilePath ->

cardano-chain-gen/test/Test/Cardano/Db/Mock/Unit/Conway.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ unitTests iom knownMigrations =
121121
, test "drepDistr rollback" Rollback.drepDistrRollback
122122
, test "sync bigger chain" Rollback.bigChain
123123
, test "rollback while db-sync is off" Rollback.restartAndRollback
124+
, test "large rollback while db-sync is off" Rollback.restartAndRollbackLarge
124125
, test "big rollback executed lazily" Rollback.lazyRollback
125126
, test "lazy rollback on restart" Rollback.lazyRollbackRestart
126127
, test "rollback while rollbacking" Rollback.doubleRollback

cardano-chain-gen/test/Test/Cardano/Db/Mock/Unit/Conway/Rollback.hs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Test.Cardano.Db.Mock.Unit.Conway.Rollback (
99
simpleRollback,
1010
bigChain,
1111
restartAndRollback,
12+
restartAndRollbackLarge,
1213
lazyRollback,
1314
lazyRollbackRestart,
1415
doubleRollback,
@@ -35,7 +36,7 @@ import Cardano.Mock.Forging.Types (PoolIndex (..), StakeIndex (..), UTxOIndex (.
3536
import Cardano.Prelude
3637
import Data.Maybe.Strict (StrictMaybe (..))
3738
import Ouroboros.Network.Block (blockPoint)
38-
import Test.Cardano.Db.Mock.Config (claFullMode, configPoolStats, conwayConfigDir, initCommandLineArgs, queryDBSync, startDBSync, stopDBSync, withCustomConfigDropDB, withFullConfigDropDB)
39+
import Test.Cardano.Db.Mock.Config (claFullMode, configPoolStats, conwayConfigDir, initCommandLineArgs, queryDBSync, startDBSync, stopDBSync, withCustomConfigDropDB, withFullConfigDropDB, withFullConfigDropDBNoFingerprint)
3940
import Test.Cardano.Db.Mock.Examples
4041
import Test.Cardano.Db.Mock.UnifiedApi
4142
import Test.Cardano.Db.Mock.Validate (assertBlockNoBackoff, assertEqQuery, assertTxCount)
@@ -94,7 +95,7 @@ bigChain =
9495

9596
restartAndRollback :: IOManager -> [(Text, Text)] -> Assertion
9697
restartAndRollback =
97-
withFullConfigDropDB conwayConfigDir testLabel $ \interpreter mockServer dbSync -> do
98+
withFullConfigDropDBNoFingerprint conwayConfigDir testLabel $ \interpreter mockServer dbSync -> do
9899
-- Forge some blocks
99100
forM_ (replicate 101 mockBlock0) (forgeNextAndSubmit interpreter mockServer)
100101

@@ -107,20 +108,49 @@ restartAndRollback =
107108
-- Wait for it to sync
108109
assertBlockNoBackoff dbSync 201
109110

110-
-- Forge some more blocks
111-
forM_ (replicate 5 mockBlock2) (forgeNextAndSubmit interpreter mockServer)
111+
-- Forge some more blocks (using mockBlock0 so the new block after rollback will have a different forger)
112+
forM_ (replicate 5 mockBlock0) (forgeNextAndSubmit interpreter mockServer)
112113
assertBlockNoBackoff dbSync 206
113114

114115
-- Rollback and restart
115116
stopDBSync dbSync
116117
void $ rollbackTo interpreter mockServer (blockPoint $ last blks)
117118
startDBSync dbSync
118119

119-
-- TODO: DBSync doesn't detect rollbacks while stopped
120-
assertBlockNoBackoff dbSync 206
120+
-- rollbackTo forges an empty block after rollback, so we expect 202 blocks
121+
-- (rollback point at 201 + the new empty block)
122+
assertBlockNoBackoff dbSync 202
121123
where
122124
testLabel = "conwayRestartAndRollback"
123125

126+
restartAndRollbackLarge :: IOManager -> [(Text, Text)] -> Assertion
127+
restartAndRollbackLarge =
128+
withFullConfigDropDBNoFingerprint conwayConfigDir testLabel $ \interpreter mockServer dbSync -> do
129+
-- Forge initial blocks
130+
forM_ (replicate 101 mockBlock0) (forgeNextAndSubmit interpreter mockServer)
131+
132+
startDBSync dbSync
133+
assertBlockNoBackoff dbSync 101
134+
135+
-- First batch: blocks to rollback to
136+
blks1 <- forM (replicate 100 mockBlock0) (forgeNextAndSubmit interpreter mockServer)
137+
assertBlockNoBackoff dbSync 201
138+
139+
-- Second batch: blocks that will be rolled back
140+
forM_ (replicate 100 mockBlock0) (forgeNextAndSubmit interpreter mockServer)
141+
assertBlockNoBackoff dbSync 301
142+
143+
-- Rollback and restart - rolling back 100 blocks
144+
stopDBSync dbSync
145+
void $ rollbackTo interpreter mockServer (blockPoint $ last blks1)
146+
startDBSync dbSync
147+
148+
-- rollbackTo forges an empty block after rollback, so we expect 202 blocks
149+
-- (rollback point at 201 + the new empty block)
150+
assertBlockNoBackoff dbSync 202
151+
where
152+
testLabel = "conwayRestartAndRollbackLarge"
153+
124154
lazyRollback :: IOManager -> [(Text, Text)] -> Assertion
125155
lazyRollback =
126156
withFullConfigDropDB conwayConfigDir testLabel $ \interpreter mockServer dbSync -> do

cardano-db-sync/src/Cardano/DbSync/Api.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,14 @@ getLatestPoints env = do
448448
case envLedgerEnv env of
449449
HasLedger hasLedgerEnv -> do
450450
snapshotPoints <- listKnownSnapshots hasLedgerEnv
451-
verifySnapshotPoint env snapshotPoints
451+
if null snapshotPoints
452+
then do
453+
-- Fallback: When no snapshots available (e.g., after restart),
454+
-- query database for recent blocks to use as intersection points
455+
lastPoints <- DB.runDbDirectSilent (envDbEnv env) DB.queryLatestPoints
456+
pure $ mapMaybe convert lastPoints
457+
else
458+
verifySnapshotPoint env snapshotPoints
452459
NoLedger _ -> do
453460
-- Brings the 5 latest.
454461
lastPoints <- DB.runDbDirectSilent (envDbEnv env) DB.queryLatestPoints

cardano-db-sync/src/Cardano/DbSync/Sync.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,11 @@ chainSyncClient metricsSetters trce latestPoints currentTip tc = do
318318
ClientPipelinedStIdle n CardanoBlock (Point CardanoBlock) (Tip CardanoBlock) IO ()
319319
go mkPipelineDecision n clientTip serverTip mPoint =
320320
case (mPoint, n, runPipelineDecision mkPipelineDecision n clientTip serverTip) of
321-
(Just points, _, _) -> drainThePipe n $ clientPipelinedStIdle clientTip points
321+
(Just points, _, _) ->
322+
-- When re-intersecting after rollback failure, reset clientTip to Origin
323+
-- if falling back to genesis, otherwise keep current clientTip
324+
let newClientTip = if points == [genesisPoint] then Origin else clientTip
325+
in drainThePipe n $ clientPipelinedStIdle newClientTip points
322326
(_, _Zero, (Request, mkPipelineDecision')) ->
323327
SendMsgRequestNext (pure ()) clientStNext
324328
where

0 commit comments

Comments
 (0)