From 948c725b09d4c9f3142674911b6a87c1a2416a66 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Fri, 14 Apr 2023 15:28:00 -0400 Subject: [PATCH] Exercise the case where some shares are duplicates --- src/Tahoe/Download.hs | 9 ++++---- test/Spec.hs | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/Tahoe/Download.hs b/src/Tahoe/Download.hs index b2b394f..f5a05d6 100644 --- a/src/Tahoe/Download.hs +++ b/src/Tahoe/Download.hs @@ -2,6 +2,7 @@ module Tahoe.Download (DownloadError (..), download) where import qualified Data.ByteString.Lazy as LB import Data.Either (rights) +import Data.List (foldl') import qualified Data.Map.Strict as Map import qualified Data.Set as Set import qualified Data.Text as T @@ -49,13 +50,13 @@ download servers Reader{verifier = Verifier{..}} openServer = if null discovered then pure $ Left NoReachableServers else - if (fromIntegral required >=) . countShares $ discovered - then pure $ Left NotEnoughShares{notEnoughSharesNeeded = fromIntegral required, notEnoughSharesFound = countShares discovered} + if (fromIntegral required >=) . countDistinctShares $ discovered + then pure $ Left NotEnoughShares{notEnoughSharesNeeded = fromIntegral required, notEnoughSharesFound = countDistinctShares discovered} else pure . Right . LB.fromStrict . encodeUtf8 . T.pack . show $ discovered where - -- Figure the total number of shares reported by all of the servers we + -- Figure the total number of distinct shares reported by all of the servers we -- asked. - countShares = sum . map (Set.size . snd) + countDistinctShares = Set.size . foldl' Set.union mempty . map snd -- Ask one server which shares it has related to the storage index in -- question. diff --git a/test/Spec.hs b/test/Spec.hs index 42c8753..7456668 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -73,6 +73,55 @@ tests = then pure . pure $ server else pure Nothing + -- Try to download the cap which requires three shares to reconstruct. + result <- liftIO $ download anns cap openServer + assertEqual + "download should fail with not enough shares" + (Left NotEnoughShares{notEnoughSharesNeeded = 3, notEnoughSharesFound = 2}) + result + , testCase "not enough distinct shares" $ do + -- If we can't recover enough *distinct* shares from the + -- configured servers then we can't possibly get enough shares to + -- recover the application data. Duplicate shares do us no good. + let anns = + Map.fromList + [ + ( "v0-abc123" + , StorageServerAnnouncement + { storageServerAnnouncementFURL = Just "somewhere" + , storageServerAnnouncementNick = Just "abc123" + , storageServerAnnouncementPermutationSeed = Nothing + } + ) + , + ( "v0-abc456" + , StorageServerAnnouncement + { storageServerAnnouncementFURL = Just "elsewhere" + , storageServerAnnouncementNick = Just "abc123" + , storageServerAnnouncementPermutationSeed = Nothing + } + ) + ] + cap = trivialCap 3 3 + + -- Three shares exist + somewhere <- memoryStorageServer + let idx = storageIndex . verifier $ cap + offset = 0 + storageServerWrite somewhere idx 0 offset "Hello world" + storageServerWrite somewhere idx 1 offset "Hello world" + -- But this one is just a duplicate of share 0 on the other + -- server. + elsewhere <- memoryStorageServer + storageServerWrite elsewhere idx 0 offset "Hello world" + + -- Make the server reachable. + let openServer furl = + pure $ case furl of + "somewhere" -> pure somewhere + "elsewhere" -> pure elsewhere + _ -> Nothing + -- Try to download the cap which requires three shares to reconstruct. result <- liftIO $ download anns cap openServer assertEqual -- GitLab