Skip to content

Commit 273f95d

Browse files
committed
Detect and rollback orphaned blocks
Orphan blocks occur when a new block does not extend the chain with the most recent block in the database, but extends it with a block before the most recent one. In this case we want to remove the orphaned blocks before adding the new one.
1 parent c2c1907 commit 273f95d

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

cardano-db-sync/src/Cardano/DbSync/Plugin/Default/Byron/Insert.hs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,17 @@ insertABlock
102102
-> ExceptT DbSyncNodeError (ReaderT SqlBackend m) ()
103103
insertABlock tracer blk tip = do
104104
meta <- liftLookupFail "insertABlock" DB.queryMeta
105-
pbid <- liftLookupFail "insertABlock" $ DB.queryBlockId (Byron.unHeaderHash $ Byron.blockPreviousHash blk)
105+
106+
(pbid, mBlock) <- liftLookupFail "insertABOBBoundary" $
107+
DB.queryBlockIdAndNo (Byron.unHeaderHash $ Byron.blockPreviousHash blk)
108+
case mBlock of
109+
Nothing -> pure () -- Previous was an EBB
110+
Just blockNo ->
111+
if blockNo < Byron.blockNumber blk
112+
then pure ()
113+
else do
114+
liftIO . logInfo tracer $ "Rollback orphan block number " <> textShow blockNo
115+
lift . void $ DB.deleteCascadeBlockNo blockNo
106116

107117
let slotsPerEpoch = 10 * DB.metaProtocolConst meta
108118

cardano-db/src/Cardano/Db/Delete.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Cardano.Db.Delete
22
( deleteCascadeBlock
3+
, deleteCascadeBlockNo
34
, deleteCascadeSlotNo
45
) where
56

@@ -23,6 +24,14 @@ deleteCascadeBlock block = do
2324
mapM_ (deleteCascade . entityKey) keys
2425
pure $ not (null keys)
2526

27+
-- | Delete a block if it exists. Returns 'True' if it did exist and has been
28+
-- deleted and 'False' if it did not exist.
29+
deleteCascadeBlockNo :: MonadIO m => Word64 -> ReaderT SqlBackend m Bool
30+
deleteCascadeBlockNo blockNo = do
31+
keys <- selectList [ BlockBlockNo ==. Just blockNo ] []
32+
mapM_ (deleteCascade . entityKey) keys
33+
pure $ not (null keys)
34+
2635
-- | Delete a block if it exists. Returns 'True' if it did exist and has been
2736
-- deleted and 'False' if it did not exist.
2837
deleteCascadeSlotNo :: MonadIO m => Word64 -> ReaderT SqlBackend m Bool

cardano-db/src/Cardano/Db/Query.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ module Cardano.Db.Query
99
, queryBlockCount
1010
, queryBlockHeight
1111
, queryBlockId
12+
, queryBlockIdAndNo
1213
, queryBlockNo
1314
, queryMainBlock
1415
, queryBlockTxCount
@@ -115,6 +116,17 @@ queryBlockId hash = do
115116
pure $ blk ^. BlockId
116117
pure $ maybeToEither (DbLookupBlockHash hash) unValue (listToMaybe res)
117118

119+
-- | Get the 'BlockId' and the 'BlockNo' associated with the given hash.
120+
-- This is is usually used with the prevHash for a block so that the back reference
121+
-- for the block can be obtained. The BlockNo is also returned so any orphaned blocks
122+
-- can be rolled back.
123+
queryBlockIdAndNo :: MonadIO m => ByteString -> ReaderT SqlBackend m (Either LookupFail (BlockId, Maybe Word64))
124+
queryBlockIdAndNo hash = do
125+
res <- select . from $ \ blk -> do
126+
where_ (blk ^. BlockHash ==. val hash)
127+
pure $ (blk ^. BlockId, blk ^. BlockBlockNo)
128+
pure $ maybeToEither (DbLookupBlockHash hash) unValue2 (listToMaybe res)
129+
118130
queryBlockNo :: MonadIO m => Word64 -> ReaderT SqlBackend m (Maybe Block)
119131
queryBlockNo blkNo = do
120132
res <- select . from $ \ blk -> do

0 commit comments

Comments
 (0)