Skip to content

[BUG] - Mismatch in ChainDB.q-s-m wrt MaxSlotNo #1870

@jasagredo

Description

@jasagredo

https://github.com/IntersectMBO/ouroboros-consensus/actions/runs/21832592717/job/62994870493?pr=1826#logs

The chain is:

Genesis -- A (0, -8986190201926803368, Valid)
        \- B (2, -1486433721842374672, Invalid) 

When the block B arrives, it is popped from the queue

TraceAddBlockEvent (PoppedBlockFromQueue (RealPoint (SlotNo 2) (TestHeaderHash (-1486433721842374672))))

and then it is ignored, because the block A has been boosted with Peras certificates, and the chainsel logic sees that it is at the same block number than the immutable tip so we should not switch:

          TraceAddBlockEvent (IgnoreBlockOlderThanImmTip (RealPoint (SlotNo 2) (TestHeaderHash (-1486433721842374672))))

However when the ChainDB is then asked what is the MaxSlotNo, it reports 2. However this answer comes from:

  curChainMaxSlotNo <-
    maxSlotNoFromWithOrigin . AF.headSlot . icWithoutTime
      <$> readTVar cdbChain
  volatileDbMaxSlotNo <- VolatileDB.getMaxSlotNo cdbVolatileDB
  queuedMaxSlotNo <- getMaxSlotNoChainSelQueue cdbChainSelQueue
  return $ curChainMaxSlotNo `max` volatileDbMaxSlotNo `max` queuedMaxSlotNo

And the block is not in the cdbChain (as we saw no AddedToCurrentChain for this block), nor in the cdbVolatileDB (as we saw no AddedBlockToVolatileDB traces for this block) so it has to be in the chain sel queue? but it was unqueued precisely by the existance of the PoppedBlockFromQueue so something fishy is going on here.

Moreover, I cannot reproduce this test failure on my machine with the same seed and GHC

❯ cabal test storage-test --test-option="-p /ChainDB q-s-m.sequential/" --test-option="--quickcheck-replay=(SMGen 15194541575572225434 13540340026014931941,80)" --test-option="--hide-successes"
Build profile: -w ghc-9.12.2 -O1
In order, the following will be built (use -v for more details):
 - ouroboros-consensus-0.28.0.0 (test:storage-test) (ephemeral targets)
Preprocessing test suite 'storage-test' for ouroboros-consensus-0.28.0.0...
Building test suite 'storage-test' for ouroboros-consensus-0.28.0.0...
Running 1 test suites...
Test suite storage-test: RUNNING...

All 1 tests passed (22.08s)
Test suite storage-test: PASS
Test suite logged to:
/home/javier/code/cardano/ouroboros-consensus/dist-newstyle/build/x86_64-linux/ghc-9.12.2/ouroboros-consensus-0.28.0.0/t/storage-test/test/ouroboros-consensus-0.28.0.0-storage-test.log
1 of 1 test suites (1 of 1 test cases) passed.

EDIT: actually, the reading from the queue happens from the set of known points:

data ChainSelQueue m blk = ChainSelQueue
  { varChainSelQueue :: TBQueue m (ChainSelMessage m blk)
  , varChainSelPoints :: StrictTVar m (MultiSet (RealPoint blk))
  }

but we only add when we add a block to the queue:

addBlockToAdd tracer (ChainSelQueue{varChainSelQueue, varChainSelPoints}) punish blk = do
  ...
  modifyTVar varChainSelPoints $ MultiSet.insert pt

and we delete when we processed a block:

processedChainSelMessage ChainSelQueue{varChainSelPoints} = \case
  ChainSelAddBlock BlockToAdd{blockToAdd = blk} ->
    modifyTVar varChainSelPoints $ MultiSet.delete (blockRealPoint blk)

which gets called immediately after the chainSelSync:

      ( \message -> do
          lift $ case message of
            ChainSelReprocessLoEBlocks _ ->
              trace PoppedReprocessLoEBlocksFromQueue
            ChainSelAddBlock BlockToAdd{blockToAdd} ->
              trace $ PoppedBlockFromQueue $ blockRealPoint blockToAdd
            ChainSelAddPerasCert cert _varProcessed ->
              traceWith cdbTracer $
                TraceAddPerasCertEvent $
                  PoppedPerasCertFromQueue (getPerasCertRound cert) (getPerasCertBoostedBlock cert)
          chainSelSync cdb message
          lift $ atomically $ processedChainSelMessage cdbChainSelQueue message
      )

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions