-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Genesis milestone 12 - Chain Sync Jumping (#1033)
The main contribution of this PR is the implementation of ChainSync Jumping (0e265c4), a mechanism to avoid overloading the honest peers in the network when one or more peers connect to them for syncing. The details of ChainSync Jumping are discussed in the [Jumping module](https://github.com/IntersectMBO/ouroboros-consensus/blob/78e16d0/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/MiniProtocol/ChainSync/Client/Jumping.hs). A range of supporting commits are provided in addition. ## More tests * The time limited leashing attack test is configured and enabled in 6c25310. This test is aimed at the GDD governor implemented in #1015. * A test to show that a node can resume syncing after being disconnected for a while has been implemented in 5d3c200. * There is a test checking that the GDD governor doesn't regret disconnecting nodes as more headers are known to it (dbbc3ab ). This was included in the previous milestone but we discovered later it wasn't checking as much as we intended. * In da7a6db and 3220e7d there is a test for ChainSync Jumping that ensures that a syncing node downloads headers from at most one peer when there is no disagreement between the peers. * There are various fixes to tests and documentation in d6f6ddf, b0ed1c8, d70e604 , cee466f, and dbbc3ab. ## GDD refinement The ability of the GDD governor to disconnect nodes has increased in dcb20f5. With respect to #1015, the GDD governor can now disconnect peers in the following scenarios: 1. when a peer has a chain that can't be denser than another chain served by another peer (before, we would disconnect the peer only if there was a denser chain); or 2. when a peer has a chain of density 0 and it claims to have more headers after the genesis window; or 3. when a peer sent a header for the last slot of the genesis window or later, and loses the density comparison to another peer (before, we would disconnect the peer only after it loses the density comparison to a peer that sent more than k headers in the genesis window). These changes help ChainSync Jumping make progress while downloading headers from only two disagreeing peers (even if both are adversarial). ## Other changes * A version of shrinking of honest schedules of messages has been implemented in 9794292. * 9572256 contains a fix to the implementation of Limit on Patience. * 915238e implements a recording tracer that doesn't affect scheduling in IOSim.
- Loading branch information
Showing
43 changed files
with
3,039 additions
and
560 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
...-diffusion/changelog.d/20240430_180423_niols_milestone_12_chain_sync_jumping.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
### Breaking | ||
|
||
- Implemented a first version of CSJ (ChainSync Jumping). (disabled by default) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
137 changes: 137 additions & 0 deletions
137
ouroboros-consensus-diffusion/test/consensus-test/Test/Consensus/Genesis/Tests/CSJ.hs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
{-# LANGUAGE LambdaCase #-} | ||
{-# LANGUAGE NamedFieldPuns #-} | ||
|
||
module Test.Consensus.Genesis.Tests.CSJ (tests) where | ||
|
||
import Control.Monad (replicateM) | ||
import Data.Containers.ListUtils (nubOrd) | ||
import Data.Functor (($>)) | ||
import Data.List (nub) | ||
import Data.Maybe (mapMaybe) | ||
import Ouroboros.Consensus.Block (blockSlot, succWithOrigin) | ||
import Ouroboros.Consensus.MiniProtocol.ChainSync.Client | ||
(TraceChainSyncClientEvent (..)) | ||
import Ouroboros.Consensus.Util.Condense (PaddingDirection (..), | ||
condenseListWithPadding) | ||
import qualified Ouroboros.Network.AnchoredFragment as AF | ||
import Test.Consensus.BlockTree (BlockTree (..)) | ||
import Test.Consensus.Genesis.Setup | ||
import Test.Consensus.Genesis.Tests.Uniform (genUniformSchedulePoints) | ||
import Test.Consensus.PeerSimulator.Run (SchedulerConfig (..), | ||
defaultSchedulerConfig) | ||
import Test.Consensus.PeerSimulator.StateView (StateView (..)) | ||
import Test.Consensus.PeerSimulator.Trace (TraceEvent (..)) | ||
import Test.Consensus.PointSchedule | ||
import Test.Consensus.PointSchedule.Peers (Peer (..), Peers (..), | ||
mkPeers) | ||
import Test.Tasty | ||
import Test.Tasty.QuickCheck | ||
import Test.Util.Orphans.IOLike () | ||
import Test.Util.TestBlock (Header, TestBlock) | ||
import Test.Util.TestEnv (adjustQuickCheckMaxSize) | ||
|
||
tests :: TestTree | ||
tests = | ||
adjustQuickCheckMaxSize (`div` 5) $ | ||
testGroup | ||
"CSJ" | ||
[ testGroup "Happy Path" | ||
[ testProperty "synchronous" $ prop_happyPath True | ||
, testProperty "asynchronous" $ prop_happyPath False | ||
] | ||
] | ||
|
||
-- | Test of the “happy path” scenario of ChainSync Jumping (CSJ). | ||
-- | ||
-- This test features one chain (ie. a block tree that is only trunk) and only | ||
-- honest peers and syncs the chain in question with CSJ enabled. What we expect | ||
-- to observe is that one of the honest peers becomes the dynamo while the | ||
-- others become jumpers. Because the jumpers will agree to all the jumps, the | ||
-- whole syncing should happen with CSJ without objectors. | ||
-- | ||
-- The final property is that headers should only ever be downloaded once and | ||
-- only from one peer (the dynamo). This is true except when almost caught-up: | ||
-- when the dynamo is caught-up, it gets disengaged and one of the jumpers takes | ||
-- its place and starts serving headers. This might lead to duplication of | ||
-- headers, but only in a window of @jumpSize@ slots near the tip of the chain. | ||
-- | ||
-- The boolean differentiates between “synchronous” and “asynchronous” | ||
-- scenarios. In a synchronous scenario, all the honest peers have the same | ||
-- schedule: they serve the chain exactly in the same way. In the asynchronous | ||
-- scenario, a random schedule is generated for each peer (but they still serve | ||
-- the same chain). | ||
prop_happyPath :: Bool -> Property | ||
prop_happyPath synchronized = | ||
forAllGenesisTest | ||
( do | ||
gt <- genChains $ pure 0 | ||
honest <- genHonestSchedule gt | ||
numOthers <- choose (1, 3) | ||
otherHonests <- if synchronized | ||
then pure $ replicate numOthers honest | ||
else replicateM numOthers (genHonestSchedule gt) | ||
pure $ gt $> mkPeers honest otherHonests | ||
) | ||
( defaultSchedulerConfig | ||
{ scEnableCSJ = True | ||
, scEnableLoE = True | ||
, scEnableLoP = True | ||
} | ||
) | ||
( -- NOTE: Shrinking makes the tests fail because the peers reject jumps | ||
-- because their TP is G. This makes them into objectors and they then | ||
-- start serving headers. | ||
\_ _ -> [] | ||
) | ||
( \gt StateView{svTrace} -> | ||
let | ||
-- The list of 'TraceDownloadedHeader' events that are not newer than | ||
-- jumpSize from the tip of the chain. These are the ones that we | ||
-- expect to see only once per header if CSJ works properly. | ||
headerDownloadEvents = | ||
mapMaybe | ||
(\case | ||
TraceChainSyncClientEvent pid (TraceDownloadedHeader hdr) | ||
| not (isNewerThanJumpSizeFromTip gt hdr) | ||
-> Just (pid, hdr) | ||
_ -> Nothing | ||
) | ||
svTrace | ||
receivedHeadersOnlyOnce = length (nub $ snd <$> headerDownloadEvents) == length headerDownloadEvents | ||
-- NOTE: If all the headers are newer than jumpSize from the tip, then | ||
-- 'headerDownloadEvents' is empty and the following condition would | ||
-- violated if we used @==@. | ||
receivedHeadersFromOnlyOnePeer = length (nubOrd $ fst <$> headerDownloadEvents) <= 1 | ||
in | ||
tabulate "" | ||
[ if headerDownloadEvents == [] | ||
then "All headers may be downloaded twice (uninteresting test)" | ||
else "There exist headers that have to be downloaded exactly once" | ||
] $ | ||
counterexample | ||
("Downloaded headers (except jumpSize slots near the tip):\n" ++ | ||
( unlines $ fmap (" " ++) $ zipWith | ||
(\peer header -> peer ++ " | " ++ header) | ||
(condenseListWithPadding PadRight $ fst <$> headerDownloadEvents) | ||
(condenseListWithPadding PadRight $ snd <$> headerDownloadEvents) | ||
) | ||
) | ||
(receivedHeadersOnlyOnce && receivedHeadersFromOnlyOnePeer) | ||
) | ||
where | ||
-- | This might seem wasteful, as we discard generated adversarial schedules. | ||
-- It actually isn't, since we call it on trees that have no branches besides | ||
-- the trunk, so no adversaries are generated. | ||
genHonestSchedule :: GenesisTest TestBlock () -> Gen (PeerSchedule TestBlock) | ||
genHonestSchedule gt = do | ||
ps <- genUniformSchedulePoints gt | ||
pure $ value $ honest ps | ||
|
||
isNewerThanJumpSizeFromTip :: GenesisTestFull TestBlock -> Header TestBlock -> Bool | ||
isNewerThanJumpSizeFromTip gt hdr = | ||
let jumpSize = csjpJumpSize $ gtCSJParams gt | ||
tipSlot = AF.headSlot $ btTrunk $ gtBlockTree gt | ||
hdrSlot = blockSlot hdr | ||
in | ||
-- Sanity check: add @1 +@ after @>@ and watch the World burn. | ||
hdrSlot + jumpSize >= succWithOrigin tipSlot |
Oops, something went wrong.