Skip to content

Commit 0f46223

Browse files
authored
UTxO-HD: Store snapshot metadata alongside its data (#1431)
# Description This PR adds snapshot metadata to the snapshotting mechanism in order for different types of snapshots to be distinguishable without needing to inspect their contents. Fixes #1416
2 parents 4412da0 + b8e285b commit 0f46223

File tree

22 files changed

+272
-203
lines changed

22 files changed

+272
-203
lines changed

ouroboros-consensus-cardano/app/DBAnalyser/Parsers.hs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import Options.Applicative
1818
import Ouroboros.Consensus.Block (SlotNo (..), WithOrigin (..))
1919
import Ouroboros.Consensus.Byron.Node (PBftSignatureThreshold (..))
2020
import Ouroboros.Consensus.Shelley.Node (Nonce (..))
21-
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots
2221

2322
{-------------------------------------------------------------------------------
2423
Parsing
@@ -42,17 +41,6 @@ parseDBAnalyserConfig = DBAnalyserConfig
4241
<*> parseValidationPolicy
4342
<*> parseAnalysis
4443
<*> parseLimit
45-
<*> flag DoDiskSnapshotChecksum NoDoDiskSnapshotChecksum (mconcat [
46-
long "no-snapshot-checksum-on-read"
47-
, help "Don't check the '.checksum' file when reading a ledger snapshot"
48-
])
49-
<*> flag DoDiskSnapshotChecksum NoDoDiskSnapshotChecksum (mconcat [
50-
long "no-snapshot-checksum-on-write"
51-
, help (unlines [ "Don't calculate the checksum and"
52-
, "write the '.checksum' file"
53-
, "when taking a ledger snapshot"
54-
])
55-
])
5644
<*> Foldable.asum [
5745
flag' V1InMem $ mconcat [
5846
long "v1-in-mem"

ouroboros-consensus-cardano/app/snapshot-converter.hs

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ data Config = Config
6565
-- ^ Which format the output snapshot must be in
6666
, outpath :: FilePath
6767
-- ^ Path to the output snapshot
68-
, writeChecksum :: Flag "DoDiskSnapshotChecksum"
69-
-- ^ Write and check checksums
70-
, checkChecksum :: Flag "DoDiskSnapshotChecksum"
7168
}
7269

7370
getCommandLineConfig :: IO (Config, BlockType)
@@ -107,18 +104,6 @@ parseConfig =
107104
, metavar "PATH-OUT"
108105
]
109106
)
110-
<*> flag DoDiskSnapshotChecksum NoDoDiskSnapshotChecksum
111-
( mconcat
112-
[ long "no-write-checksum"
113-
, help "Disable writing checksums"
114-
]
115-
)
116-
<*> flag DoDiskSnapshotChecksum NoDoDiskSnapshotChecksum
117-
( mconcat
118-
[ long "no-read-checksum"
119-
, help "Disable checking checksums"
120-
]
121-
)
122107

123108
-- Helpers
124109

@@ -140,13 +125,15 @@ data Error blk
140125
| TablesCantDeserializeError DeserialiseFailure
141126
| TablesTrailingBytes
142127
| SnapshotFormatMismatch Format String
128+
| ReadSnapshotCRCError FsPath CRCError
143129
deriving Exception
144130

145131
instance StandardHash blk => Show (Error blk) where
146132
show (SnapshotError err) = "Couldn't deserialize the snapshot. Are you running the same node version that created the snapshot? " <> show err
147133
show (TablesCantDeserializeError err) = "Couldn't deserialize the tables: " <> show err
148134
show TablesTrailingBytes = "Malformed tables, there are trailing bytes!"
149135
show (SnapshotFormatMismatch expected err) = "The input snapshot does not seem to correspond to the input format:\n\t" <> show expected <> "\n\tThe provided path " <> err
136+
show (ReadSnapshotCRCError fp err) = "An error occurred while reading the snapshot checksum at " <> show fp <> ": \n\t" <> show err
150137

151138
checkSnapshotFileStructure :: Format -> FsPath -> SomeHasFS IO -> ExceptT (Error blk) IO ()
152139
checkSnapshotFileStructure m p (SomeHasFS fs) = case m of
@@ -189,22 +176,23 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
189176
case from config of
190177
Legacy -> do
191178
checkSnapshotFileStructure Legacy path fs
192-
(st, mbChecksumAsRead) <-
179+
(st, checksumAsRead) <-
193180
first unstowLedgerTables
194181
<$> withExceptT
195182
(SnapshotError . InitFailureRead . ReadSnapshotFailed)
196-
(readExtLedgerState fs (decodeDiskExtLedgerState ccfg) decode checkChecksum path)
197-
Monad.when (getFlag checkChecksum) $ do
198-
let crcPath = path <.> "checksum"
183+
(readExtLedgerState fs (decodeDiskExtLedgerState ccfg) decode path)
184+
let crcPath = path <.> "checksum"
185+
crcFileExists <- Trans.lift $ doesFileExist hasFS crcPath
186+
Monad.when crcFileExists $ do
199187
snapshotCRC <-
200-
withExceptT (SnapshotError . InitFailureRead . ReadSnapshotCRCError crcPath) $
188+
withExceptT (ReadSnapshotCRCError crcPath) $
201189
readCRC hasFS crcPath
202-
Monad.when (mbChecksumAsRead /= Just snapshotCRC) $
190+
Monad.when (checksumAsRead /= snapshotCRC) $
203191
throwError $ SnapshotError $ InitFailureRead ReadSnapshotDataCorruption
204192
pure (forgetLedgerTables st, projectLedgerTables st)
205193
Mem -> do
206194
checkSnapshotFileStructure Mem path fs
207-
(ls, _) <- withExceptT SnapshotError $ V2.loadSnapshot rr ccfg fs checkChecksum ds
195+
(ls, _) <- withExceptT SnapshotError $ V2.loadSnapshot rr ccfg fs ds
208196
let h = V2.currentHandle ls
209197
(V2.state h,) <$> Trans.lift (V2.readAll (V2.tables h))
210198
LMDB -> do
@@ -216,11 +204,8 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
216204
(V1.LMDBBackingStoreArgs tempFP defaultLMDBLimits Dict.Dict)
217205
ccfg
218206
(V1.SnapshotsFS fs)
219-
checkChecksum
220207
ds
221208
(V1.current dbch,) <$> Trans.lift (V1.bsReadAll bstore (V1.changelogLastFlushedState dbch))
222-
where
223-
Config { checkChecksum } = config
224209
load _ _ _ _ = error "Malformed input path!"
225210

226211
store ::
@@ -238,21 +223,18 @@ store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS),
238223
case to config of
239224
Legacy -> do
240225
crc <- writeExtLedgerState fs (encodeDiskExtLedgerState ccfg) path (stowLedgerTables $ state `withLedgerTables` tbs)
241-
Monad.when (getFlag writeChecksum) $
242-
withFile hasFS (path <.> "checksum") (WriteMode MustBeNew) $ \h ->
243-
Monad.void $ hPutAll hasFS h . BS.toLazyByteString . BS.word32HexFixed $ getCRC crc
226+
withFile hasFS (path <.> "checksum") (WriteMode MustBeNew) $ \h ->
227+
Monad.void $ hPutAll hasFS h . BS.toLazyByteString . BS.word32HexFixed $ getCRC crc
244228
Mem -> do
245229
lseq <- V2.empty state tbs $ V2.newInMemoryLedgerTablesHandle fs
246230
let h = V2.currentHandle lseq
247-
Monad.void $ V2.takeSnapshot ccfg nullTracer fs suffix writeChecksum h
231+
Monad.void $ V2.takeSnapshot ccfg nullTracer fs suffix h
248232
LMDB -> do
249233
chlog <- newTVarIO (V1.empty state)
250234
lock <- V1.mkLedgerDBLock
251235
bs <- V1.newLMDBBackingStore nullTracer defaultLMDBLimits (V1.LiveLMDBFS tempFS) (V1.SnapshotsFS fs) (V1.InitFromValues (pointSlot $ getTip state) state tbs)
252236
Monad.void $ V1.withReadLock lock $ do
253-
V1.takeSnapshot chlog ccfg nullTracer (V1.SnapshotsFS fs) bs suffix writeChecksum
254-
where
255-
Config { writeChecksum } = config
237+
V1.takeSnapshot chlog ccfg nullTracer (V1.SnapshotsFS fs) bs suffix
256238
store _ _ _ _ = error "Malformed output path!"
257239

258240
main :: IO ()

ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Run.hs

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import qualified Ouroboros.Consensus.Storage.ChainDB.Impl.Args as ChainDB
3434
import qualified Ouroboros.Consensus.Storage.ImmutableDB as ImmutableDB
3535
import qualified Ouroboros.Consensus.Storage.ImmutableDB.Stream as ImmutableDB
3636
import qualified Ouroboros.Consensus.Storage.LedgerDB as LedgerDB
37-
import qualified Ouroboros.Consensus.Storage.LedgerDB.Snapshots as LedgerDB
3837
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1 as LedgerDB.V1
3938
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.Args as LedgerDB.V1
4039
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.BackingStore.Impl.LMDB as LMDB
@@ -149,37 +148,19 @@ analyse dbaConfig args =
149148
args'' =
150149
args' {
151150
ChainDB.cdbLgrDbArgs =
152-
(\x -> x {
153-
LedgerDB.lgrSnapshotPolicyArgs =
154-
(\y -> y {
155-
LedgerDB.spaDoChecksum = diskSnapshotChecksumOnRead
156-
})
157-
$ LedgerDB.lgrSnapshotPolicyArgs x
158-
, LedgerDB.lgrConfig =
151+
(\x -> x
152+
{ LedgerDB.lgrConfig =
159153
LedgerDB.LedgerDbCfg
160154
(SecurityParam (knownNonZeroBounded @1))
161155
(LedgerDB.ledgerDbCfg $ LedgerDB.lgrConfig x)
162156
OmitLedgerEvents
163-
}
157+
}
164158
)
165159
(ChainDB.cdbLgrDbArgs args')
166160
}
167161
chainDbArgs = maybeValidateAll $ ChainDB.updateTracer chainDBTracer args''
168162
immutableDbArgs = ChainDB.cdbImmDbArgs chainDbArgs
169-
args''' =
170-
args'' {
171-
ChainDB.cdbLgrDbArgs =
172-
(\x -> x {
173-
LedgerDB.lgrSnapshotPolicyArgs =
174-
(\y -> y {
175-
LedgerDB.spaDoChecksum = diskSnapshotChecksumOnWrite
176-
})
177-
$ LedgerDB.lgrSnapshotPolicyArgs x
178-
}
179-
)
180-
(ChainDB.cdbLgrDbArgs args'')
181-
}
182-
ldbArgs = ChainDB.cdbLgrDbArgs args'''
163+
ldbArgs = ChainDB.cdbLgrDbArgs args''
183164

184165
withImmutableDB immutableDbArgs $ \(immutableDB, internal) -> do
185166
SomeAnalysis (Proxy :: Proxy startFrom) ana <- pure $ runAnalysis analysis
@@ -219,8 +200,6 @@ analyse dbaConfig args =
219200
, validation
220201
, verbose
221202
, ldbBackend
222-
, diskSnapshotChecksumOnRead
223-
, diskSnapshotChecksumOnWrite
224203
} = dbaConfig
225204

226205
SelectImmutableDB startSlot = selectDB

ouroboros-consensus-cardano/src/unstable-cardano-tools/Cardano/Tools/DBAnalyser/Types.hs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ data SelectDB =
1111
SelectImmutableDB (WithOrigin SlotNo)
1212

1313
data DBAnalyserConfig = DBAnalyserConfig {
14-
dbDir :: FilePath
15-
, verbose :: Bool
16-
, selectDB :: SelectDB
17-
, validation :: Maybe ValidateBlocks
18-
, analysis :: AnalysisName
19-
, confLimit :: Limit
20-
, diskSnapshotChecksumOnRead :: Flag "DoDiskSnapshotChecksum"
21-
, diskSnapshotChecksumOnWrite :: Flag "DoDiskSnapshotChecksum"
22-
, ldbBackend :: LedgerDBBackend
14+
dbDir :: FilePath
15+
, verbose :: Bool
16+
, selectDB :: SelectDB
17+
, validation :: Maybe ValidateBlocks
18+
, analysis :: AnalysisName
19+
, confLimit :: Limit
20+
, ldbBackend :: LedgerDBBackend
2321
}
2422

2523
data AnalysisName =

ouroboros-consensus-cardano/test/tools-test/Main.hs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import qualified Cardano.Tools.DBSynthesizer.Run as DBSynthesizer
88
import Cardano.Tools.DBSynthesizer.Types
99
import Ouroboros.Consensus.Block
1010
import Ouroboros.Consensus.Cardano.Block
11-
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots
1211
import qualified Test.Cardano.Tools.Headers
1312
import Test.Tasty
1413
import Test.Tasty.HUnit
@@ -70,8 +69,6 @@ testAnalyserConfig =
7069
, validation = Just ValidateAllBlocks
7170
, analysis = CountBlocks
7271
, confLimit = Unlimited
73-
, diskSnapshotChecksumOnRead = NoDoDiskSnapshotChecksum
74-
, diskSnapshotChecksumOnWrite = NoDoDiskSnapshotChecksum
7572
}
7673

7774
testBlockArgs :: Cardano.Args (CardanoBlock StandardCrypto)

ouroboros-consensus/ouroboros-consensus.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ library
296296

297297
build-depends:
298298
FailT ^>=0.1.2,
299+
aeson,
299300
base >=4.14 && <4.22,
300301
base-deriving-via,
301302
base16-bytestring,
@@ -705,6 +706,7 @@ test-suite storage-test
705706
Test.Ouroboros.Storage.ImmutableDB.StateMachine
706707
Test.Ouroboros.Storage.LedgerDB
707708
Test.Ouroboros.Storage.LedgerDB.Serialisation
709+
Test.Ouroboros.Storage.LedgerDB.Snapshots
708710
Test.Ouroboros.Storage.LedgerDB.SnapshotPolicy
709711
Test.Ouroboros.Storage.LedgerDB.StateMachine
710712
Test.Ouroboros.Storage.LedgerDB.StateMachine.TestBlock
@@ -722,6 +724,7 @@ test-suite storage-test
722724

723725
build-depends:
724726
QuickCheck,
727+
aeson,
725728
base,
726729
bifunctors,
727730
binary,

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB.hs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import Ouroboros.Consensus.Storage.ImmutableDB.Stream
2626
import Ouroboros.Consensus.Storage.LedgerDB.API
2727
import Ouroboros.Consensus.Storage.LedgerDB.Args
2828
import Ouroboros.Consensus.Storage.LedgerDB.Forker
29-
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots
3029
import Ouroboros.Consensus.Storage.LedgerDB.TraceEvent
3130
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1 as V1
3231
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2 as V2
@@ -123,7 +122,6 @@ openDBInternal args@(LedgerDbArgs { lgrHasFS = SomeHasFS fs }) initDb stream rep
123122
replayGoal
124123
initDb
125124
lgrStartSnapshot
126-
doDiskSnapshotChecksum
127125
(ledgerDb, internal) <- mkLedgerDb initDb db
128126
return (ledgerDb, replayCounter, internal)
129127

@@ -137,5 +135,3 @@ openDBInternal args@(LedgerDbArgs { lgrHasFS = SomeHasFS fs }) initDb stream rep
137135

138136
replayTracer = LedgerReplayEvent >$< lgrTracer
139137
snapTracer = LedgerDBSnapshotEvent >$< lgrTracer
140-
141-
SnapshotPolicyArgs _ _ doDiskSnapshotChecksum = lgrSnapshotPolicyArgs args

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB/API.hs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ type InitDB :: Type -> (Type -> Type) -> Type -> Type
465465
data InitDB db m blk = InitDB {
466466
initFromGenesis :: !(m db)
467467
-- ^ Create a DB from the genesis state
468-
, initFromSnapshot :: !(Flag "DoDiskSnapshotChecksum" -> DiskSnapshot -> m (Either (SnapshotFailure blk) (db, RealPoint blk)))
468+
, initFromSnapshot :: !(DiskSnapshot -> m (Either (SnapshotFailure blk) (db, RealPoint blk)))
469469
-- ^ Create a DB from a Snapshot
470470
, closeDb :: !(db -> m ())
471471
-- ^ Closing the database, to be reopened again with a different snapshot or
@@ -516,7 +516,6 @@ initialize ::
516516
-> Point blk
517517
-> InitDB db m blk
518518
-> Maybe DiskSnapshot
519-
-> Flag "DoDiskSnapshotChecksum"
520519
-> m (InitLog blk, db, Word64)
521520
initialize replayTracer
522521
snapTracer
@@ -525,22 +524,20 @@ initialize replayTracer
525524
stream
526525
replayGoal
527526
dbIface
528-
fromSnapshot
529-
doDoDiskSnapshotChecksum =
527+
fromSnapshot =
530528
case fromSnapshot of
531-
Nothing -> listSnapshots hasFS >>= tryNewestFirst doDoDiskSnapshotChecksum id
532-
Just snap -> tryNewestFirst doDoDiskSnapshotChecksum id [snap]
529+
Nothing -> listSnapshots hasFS >>= tryNewestFirst id
530+
Just snap -> tryNewestFirst id [snap]
533531
where
534532
InitDB {initFromGenesis, initFromSnapshot, closeDb} = dbIface
535533

536-
tryNewestFirst :: Flag "DoDiskSnapshotChecksum"
537-
-> (InitLog blk -> InitLog blk)
534+
tryNewestFirst :: (InitLog blk -> InitLog blk)
538535
-> [DiskSnapshot]
539536
-> m ( InitLog blk
540537
, db
541538
, Word64
542539
)
543-
tryNewestFirst _ acc [] = do
540+
tryNewestFirst acc [] = do
544541
-- We're out of snapshots. Start at genesis
545542
traceWith (TraceReplayStartEvent >$< replayTracer) ReplayFromGenesis
546543
let replayTracer'' = decorateReplayTracerWithStart (Point Origin) replayTracer'
@@ -564,24 +561,38 @@ initialize replayTracer
564561
, replayed
565562
)
566563

567-
tryNewestFirst doChecksum acc allSnapshot@(s:ss) = do
568-
eInitDb <- initFromSnapshot doChecksum s
564+
tryNewestFirst acc (s:ss) = do
565+
eInitDb <- initFromSnapshot s
569566
case eInitDb of
570-
-- If a checksum file is missing for a snapshot,
571-
-- issue a warning and retry the same snapshot
572-
-- ignoring the checksum
573-
Left (InitFailureRead (ReadSnapshotCRCError _ CRCNoFile)) -> do
574-
traceWith snapTracer $ SnapshotMissingChecksum s
575-
tryNewestFirst NoDoDiskSnapshotChecksum acc allSnapshot
567+
-- If the snapshot is missing a metadata file, issue a warning and try
568+
-- the next oldest snapshot
569+
Left err@(InitFailureRead (ReadMetadataError _ MetadataFileDoesNotExist)) -> do
570+
traceWith snapTracer $ SnapshotMetadataMissing s
571+
tryNewestFirst (acc . InitFailure s err) ss
572+
573+
-- If the snapshot's backend is incorrect, issue a warning and try
574+
-- the next oldest snapshot
575+
Left err@(InitFailureRead (ReadMetadataError _ MetadataBackendMismatch)) -> do
576+
traceWith snapTracer $ SnapshotMetadataBackendMismatch s
577+
tryNewestFirst (acc . InitFailure s err) ss
578+
579+
-- If the snapshot has a checksum that doesn't match the actual data,
580+
-- issue a warning, delete it, and try the next oldest snapshot
581+
Left err@(InitFailureRead ReadSnapshotDataCorruption) -> do
582+
traceWith snapTracer $ InvalidSnapshot s err
583+
Monad.when (diskSnapshotIsTemporary s) $ do
584+
traceWith snapTracer $ DeletedSnapshot s
585+
deleteSnapshot hasFS s
586+
tryNewestFirst (acc . InitFailure s err) ss
576587

577588
-- If we fail to use this snapshot for any other reason, delete it and
578589
-- try an older one
579590
Left err -> do
580-
Monad.when (diskSnapshotIsTemporary s || err == InitFailureGenesis) $
591+
Monad.when (diskSnapshotIsTemporary s || err == InitFailureGenesis) $ do
592+
traceWith snapTracer $ DeletedSnapshot s
581593
deleteSnapshot hasFS s
582594
traceWith snapTracer . InvalidSnapshot s $ err
583-
-- reset checksum flag to the initial state after failure
584-
tryNewestFirst doChecksum (acc . InitFailure s err) ss
595+
tryNewestFirst (acc . InitFailure s err) ss
585596

586597
Right (initDb, pt) -> do
587598
let pt' = realPointToPoint pt
@@ -600,7 +611,7 @@ initialize replayTracer
600611
traceWith snapTracer . InvalidSnapshot s $ err
601612
Monad.when (diskSnapshotIsTemporary s) $ deleteSnapshot hasFS s
602613
closeDb initDb
603-
tryNewestFirst doChecksum (acc . InitFailure s err) ss
614+
tryNewestFirst (acc . InitFailure s err) ss
604615
Right (db, replayed) -> do
605616
db' <- pruneDb dbIface db
606617
return (acc (InitFromSnapshot s pt), db', replayed)
@@ -762,4 +773,4 @@ type LedgerSupportsLedgerDB blk =
762773
-- 1. @0@ in places where it is necessary
763774
-- 2. the security parameter as is, in other places
764775
data LedgerDbPrune = LedgerDbPruneAll | LedgerDbPruneKeeping SecurityParam
765-
deriving Show
776+
deriving Show

0 commit comments

Comments
 (0)