Skip to content

Commit 9279da4

Browse files
tbagrel1amesgen
authored andcommitted
Introduce the PerasCertDiffusion protocol (instance of ObjectDiffusion), and the associated smoke test
1 parent c734c36 commit 9279da4

File tree

5 files changed

+243
-0
lines changed

5 files changed

+243
-0
lines changed

ouroboros-consensus/ouroboros-consensus.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ library
185185
Ouroboros.Consensus.MiniProtocol.LocalTxSubmission.Server
186186
Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.Inbound
187187
Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.API
188+
Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.PerasCert
188189
Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.Outbound
190+
Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.PerasCert
189191
Ouroboros.Consensus.Node.GsmState
190192
Ouroboros.Consensus.Node.InitStorage
191193
Ouroboros.Consensus.Node.NetworkProtocolVersion
@@ -596,6 +598,7 @@ test-suite consensus-test
596598
Test.Consensus.MiniProtocol.ChainSync.CSJ
597599
Test.Consensus.MiniProtocol.ChainSync.Client
598600
Test.Consensus.MiniProtocol.LocalStateQuery.Server
601+
Test.Consensus.MiniProtocol.ObjectDiffusion.PerasCert.Smoke
599602
Test.Consensus.MiniProtocol.ObjectDiffusion.Smoke
600603
Test.Consensus.Peras.WeightSnapshot
601604
Test.Consensus.Util.MonadSTM.NormalForm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
-- | Instantiate 'ObjectPoolReader' and 'ObjectPoolWriter' using Peras
2+
-- certificates from the 'PerasCertDB' (or the 'ChainDB' which is wrapping the
3+
-- 'PerasCertDB').
4+
module Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.PerasCert
5+
( makePerasCertPoolReaderFromCertDB
6+
, makePerasCertPoolWriterFromCertDB
7+
, makePerasCertPoolReaderFromChainDB
8+
, makePerasCertPoolWriterFromChainDB
9+
) where
10+
11+
import Ouroboros.Consensus.Block
12+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.API
13+
import Ouroboros.Consensus.Storage.ChainDB.API (ChainDB)
14+
import qualified Ouroboros.Consensus.Storage.ChainDB.API as ChainDB
15+
import Ouroboros.Consensus.Storage.PerasCertDB.API
16+
( PerasCertDB
17+
, PerasCertSnapshot
18+
, PerasCertTicketNo
19+
)
20+
import qualified Ouroboros.Consensus.Storage.PerasCertDB.API as PerasCertDB
21+
import Ouroboros.Consensus.Util.IOLike
22+
23+
makePerasCertPoolReaderFromSnapshot ::
24+
(IOLike m, StandardHash blk) =>
25+
STM m (PerasCertSnapshot blk) ->
26+
ObjectPoolReader PerasRoundNo (PerasCert blk) PerasCertTicketNo m
27+
makePerasCertPoolReaderFromSnapshot getCertSnapshot =
28+
ObjectPoolReader
29+
{ oprObjectId = perasCertRound
30+
, oprZeroTicketNo = PerasCertDB.zeroPerasCertTicketNo
31+
, oprObjectsAfter = \lastKnown limit -> do
32+
certSnapshot <- getCertSnapshot
33+
pure $
34+
take (fromIntegral limit) $
35+
[ (ticketNo, perasCertRound cert, pure cert)
36+
| (cert, ticketNo) <- PerasCertDB.getCertsAfter certSnapshot lastKnown
37+
]
38+
}
39+
40+
makePerasCertPoolReaderFromCertDB ::
41+
(IOLike m, StandardHash blk) =>
42+
PerasCertDB m blk -> ObjectPoolReader PerasRoundNo (PerasCert blk) PerasCertTicketNo m
43+
makePerasCertPoolReaderFromCertDB perasCertDB =
44+
makePerasCertPoolReaderFromSnapshot (PerasCertDB.getCertSnapshot perasCertDB)
45+
46+
makePerasCertPoolWriterFromCertDB ::
47+
(StandardHash blk, MonadSTM m) =>
48+
PerasCertDB m blk -> ObjectPoolWriter PerasRoundNo (PerasCert blk) m
49+
makePerasCertPoolWriterFromCertDB perasCertDB =
50+
ObjectPoolWriter
51+
{ opwObjectId = perasCertRound
52+
, opwAddObjects =
53+
mapM_ $ PerasCertDB.addCert perasCertDB
54+
, opwHasObject = do
55+
certSnapshot <- atomically $ PerasCertDB.getCertSnapshot perasCertDB
56+
pure $ PerasCertDB.containsCert certSnapshot
57+
}
58+
59+
makePerasCertPoolReaderFromChainDB ::
60+
(IOLike m, StandardHash blk) =>
61+
ChainDB m blk -> ObjectPoolReader PerasRoundNo (PerasCert blk) PerasCertTicketNo m
62+
makePerasCertPoolReaderFromChainDB chainDB =
63+
makePerasCertPoolReaderFromSnapshot (ChainDB.getPerasCertSnapshot chainDB)
64+
65+
makePerasCertPoolWriterFromChainDB ::
66+
(StandardHash blk, MonadSTM m) =>
67+
ChainDB m blk -> ObjectPoolWriter PerasRoundNo (PerasCert blk) m
68+
makePerasCertPoolWriterFromChainDB chainDB =
69+
ObjectPoolWriter
70+
{ opwObjectId = perasCertRound
71+
, opwAddObjects =
72+
mapM_ $ ChainDB.addPerasCertAsync chainDB
73+
, opwHasObject = do
74+
certSnapshot <- atomically $ ChainDB.getPerasCertSnapshot chainDB
75+
pure $ PerasCertDB.containsCert certSnapshot
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-- | This module defines type aliases for the ObjectDiffusion protocol applied
2+
-- to PerasCert diffusion.
3+
module Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.PerasCert
4+
( TracePerasCertDiffusionInbound
5+
, TracePerasCertDiffusionOutbound
6+
, PerasCertPoolReader
7+
, PerasCertPoolWriter
8+
, PerasCertDiffusionInboundPipelined
9+
, PerasCertDiffusionOutbound
10+
) where
11+
12+
import Ouroboros.Consensus.Block
13+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.Inbound
14+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.API
15+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.Outbound
16+
import Ouroboros.Consensus.Storage.PerasCertDB.API
17+
import Ouroboros.Network.Protocol.ObjectDiffusion.Inbound (ObjectDiffusionInboundPipelined)
18+
import Ouroboros.Network.Protocol.ObjectDiffusion.Outbound (ObjectDiffusionOutbound)
19+
20+
type TracePerasCertDiffusionInbound blk =
21+
TraceObjectDiffusionInbound PerasRoundNo (PerasCert blk)
22+
23+
type TracePerasCertDiffusionOutbound blk =
24+
TraceObjectDiffusionOutbound PerasRoundNo (PerasCert blk)
25+
26+
type PerasCertPoolReader blk m =
27+
ObjectPoolReader PerasRoundNo (PerasCert blk) PerasCertTicketNo m
28+
29+
type PerasCertPoolWriter blk m =
30+
ObjectPoolWriter PerasRoundNo (PerasCert blk) m
31+
32+
type PerasCertDiffusionInboundPipelined blk m a =
33+
ObjectDiffusionInboundPipelined PerasRoundNo (PerasCert blk) m a
34+
35+
type PerasCertDiffusionOutbound blk m a =
36+
ObjectDiffusionOutbound PerasRoundNo (PerasCert blk) m a

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import qualified Test.Consensus.MiniProtocol.BlockFetch.Client (tests)
1616
import qualified Test.Consensus.MiniProtocol.ChainSync.CSJ (tests)
1717
import qualified Test.Consensus.MiniProtocol.ChainSync.Client (tests)
1818
import qualified Test.Consensus.MiniProtocol.LocalStateQuery.Server (tests)
19+
import qualified Test.Consensus.MiniProtocol.ObjectDiffusion.PerasCert.Smoke (tests)
1920
import qualified Test.Consensus.MiniProtocol.ObjectDiffusion.Smoke (tests)
2021
import qualified Test.Consensus.Peras.WeightSnapshot (tests)
2122
import qualified Test.Consensus.Util.MonadSTM.NormalForm (tests)
@@ -39,6 +40,7 @@ tests =
3940
, Test.Consensus.MiniProtocol.ChainSync.CSJ.tests
4041
, Test.Consensus.MiniProtocol.ChainSync.Client.tests
4142
, Test.Consensus.MiniProtocol.ObjectDiffusion.Smoke.tests
43+
, Test.Consensus.MiniProtocol.ObjectDiffusion.PerasCert.Smoke.tests
4244
, Test.Consensus.MiniProtocol.LocalStateQuery.Server.tests
4345
, testGroup
4446
"Mempool"
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
{-# LANGUAGE FlexibleContexts #-}
2+
{-# LANGUAGE FlexibleInstances #-}
3+
{-# LANGUAGE MultiParamTypeClasses #-}
4+
{-# LANGUAGE NamedFieldPuns #-}
5+
{-# LANGUAGE RankNTypes #-}
6+
{-# LANGUAGE TypeApplications #-}
7+
{-# LANGUAGE UndecidableInstances #-}
8+
{-# OPTIONS_GHC -Wno-orphans #-}
9+
10+
module Test.Consensus.MiniProtocol.ObjectDiffusion.PerasCert.Smoke (tests) where
11+
12+
import Control.Tracer (contramap, nullTracer)
13+
import Data.Functor.Identity (Identity (..))
14+
import qualified Data.List.NonEmpty as NE
15+
import Network.TypedProtocol.Driver.Simple (runPeer, runPipelinedPeer)
16+
import Ouroboros.Consensus.Block.SupportsPeras
17+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.API
18+
import Ouroboros.Consensus.MiniProtocol.ObjectDiffusion.ObjectPool.PerasCert
19+
import Ouroboros.Consensus.Storage.PerasCertDB.API
20+
( AddPerasCertResult (..)
21+
, PerasCertDB
22+
, PerasCertTicketNo
23+
)
24+
import qualified Ouroboros.Consensus.Storage.PerasCertDB.API as PerasCertDB
25+
import qualified Ouroboros.Consensus.Storage.PerasCertDB.Impl as PerasCertDB
26+
import Ouroboros.Consensus.Util.IOLike
27+
import Ouroboros.Network.Block (Point (..), SlotNo (SlotNo), StandardHash)
28+
import Ouroboros.Network.Point (Block (Block), WithOrigin (..))
29+
import Ouroboros.Network.Protocol.ObjectDiffusion.Codec
30+
import Ouroboros.Network.Protocol.ObjectDiffusion.Inbound
31+
( objectDiffusionInboundServerPeerPipelined
32+
)
33+
import Ouroboros.Network.Protocol.ObjectDiffusion.Outbound (objectDiffusionOutboundClientPeer)
34+
import Test.Consensus.MiniProtocol.ObjectDiffusion.Smoke
35+
( ListWithUniqueIds (..)
36+
, ProtocolConstants
37+
, WithId
38+
, getId
39+
, prop_smoke_object_diffusion
40+
)
41+
import Test.QuickCheck
42+
import Test.Tasty
43+
import Test.Tasty.QuickCheck (testProperty)
44+
import Test.Util.TestBlock
45+
46+
tests :: TestTree
47+
tests =
48+
testGroup
49+
"ObjectDiffusion.PerasCert.Smoke"
50+
[ testProperty "PerasCertDiffusion smoke test" prop_smoke
51+
]
52+
53+
instance Arbitrary (Point TestBlock) where
54+
arbitrary =
55+
-- Sometimes pick the genesis point
56+
frequency
57+
[ (1, pure $ Point Origin)
58+
,
59+
( 4
60+
, do
61+
slotNo <- SlotNo <$> arbitrary
62+
hash <- TestHash . NE.fromList . getNonEmpty <$> arbitrary
63+
pure $ Point (At (Block slotNo hash))
64+
)
65+
]
66+
67+
instance Arbitrary (Point blk) => Arbitrary (PerasCert blk) where
68+
arbitrary = do
69+
pcCertRound <- PerasRoundNo <$> arbitrary
70+
pcCertBoostedBlock <- arbitrary
71+
pure $ PerasCert{pcCertRound, pcCertBoostedBlock}
72+
73+
instance WithId (PerasCert blk) PerasRoundNo where
74+
getId = pcCertRound
75+
76+
newCertDB :: (IOLike m, StandardHash blk) => [PerasCert blk] -> m (PerasCertDB m blk)
77+
newCertDB certs = do
78+
db <- PerasCertDB.openDB (PerasCertDB.PerasCertDbArgs @Identity nullTracer)
79+
mapM_
80+
( \cert -> do
81+
result <- PerasCertDB.addCert db cert
82+
case result of
83+
AddedPerasCertToDB -> pure ()
84+
PerasCertAlreadyInDB -> throwIO (userError "Expected AddedPerasCertToDB, but cert was already in DB")
85+
)
86+
certs
87+
pure db
88+
89+
prop_smoke :: ProtocolConstants -> ListWithUniqueIds (PerasCert TestBlock) PerasRoundNo -> Property
90+
prop_smoke protocolConstants (ListWithUniqueIds certs) =
91+
prop_smoke_object_diffusion protocolConstants certs runOutboundPeer runInboundPeer mkPoolInterfaces
92+
where
93+
runOutboundPeer outbound outboundChannel tracer =
94+
runPeer
95+
((\x -> "Outbound (Client): " ++ show x) `contramap` tracer)
96+
codecObjectDiffusionId
97+
outboundChannel
98+
(objectDiffusionOutboundClientPeer outbound)
99+
>> pure ()
100+
runInboundPeer inbound inboundChannel tracer =
101+
runPipelinedPeer
102+
((\x -> "Inbound (Server): " ++ show x) `contramap` tracer)
103+
codecObjectDiffusionId
104+
inboundChannel
105+
(objectDiffusionInboundServerPeerPipelined inbound)
106+
>> pure ()
107+
mkPoolInterfaces ::
108+
forall m.
109+
IOLike m =>
110+
m
111+
( ObjectPoolReader PerasRoundNo (PerasCert TestBlock) PerasCertTicketNo m
112+
, ObjectPoolWriter PerasRoundNo (PerasCert TestBlock) m
113+
, m [PerasCert TestBlock]
114+
)
115+
mkPoolInterfaces = do
116+
outboundPool <- newCertDB certs
117+
inboundPool <- newCertDB []
118+
119+
let outboundPoolReader = makePerasCertPoolReaderFromCertDB outboundPool
120+
inboundPoolWriter = makePerasCertPoolWriterFromCertDB inboundPool
121+
getAllInboundPoolContent = do
122+
snap <- atomically $ PerasCertDB.getCertSnapshot inboundPool
123+
let rawContent = PerasCertDB.getCertsAfter snap (PerasCertDB.zeroPerasCertTicketNo)
124+
pure $ fst <$> rawContent
125+
126+
return (outboundPoolReader, inboundPoolWriter, getAllInboundPoolContent)

0 commit comments

Comments
 (0)