{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Test.Ouroboros.Network.TxSubmission.AppV1 (tests) where
import Prelude hiding (seq)
import NoThunks.Class
import Control.Concurrent.Class.MonadMVar (MonadMVar)
import Control.Concurrent.Class.MonadSTM
import Control.Monad (unless, void)
import Control.Monad.Class.MonadAsync
import Control.Monad.Class.MonadFork
import Control.Monad.Class.MonadSay
import Control.Monad.Class.MonadST
import Control.Monad.Class.MonadThrow
import Control.Monad.Class.MonadTime.SI
import Control.Monad.Class.MonadTimer.SI
import Control.Monad.IOSim hiding (SimResult)
import Control.Tracer (Tracer (..), contramap, nullTracer)
import Data.ByteString.Lazy qualified as BSL
import Data.Function (on)
import Data.List (intercalate, nubBy)
import Data.Maybe (fromMaybe)
import Network.TypedProtocol.Codec (CodecF (..))
import Ouroboros.Network.Channel
import Ouroboros.Network.ControlMessage (ControlMessage (..), ControlMessageSTM)
import Ouroboros.Network.Driver
import Ouroboros.Network.Protocol.Limits (sizeLimitForState)
import Ouroboros.Network.Protocol.TxSubmission2.Client
import Ouroboros.Network.Protocol.TxSubmission2.Codec
import Ouroboros.Network.Protocol.TxSubmission2.Server
import Ouroboros.Network.Protocol.TxSubmission2.Type
import Ouroboros.Network.TxSubmission.Inbound.V1
import Ouroboros.Network.TxSubmission.Inbound.V2.Policy (max_TX_SIZE)
import Ouroboros.Network.TxSubmission.Inbound.V2.Types
(const_MAX_TX_SIZE_DISCREPANCY)
import Ouroboros.Network.TxSubmission.Outbound
import Ouroboros.Network.Util.ShowProxy
import Test.QuickCheck
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (testProperty)
import Test.Ouroboros.Network.TxSubmission.SizedBytes (SizedBytes (..),
codec_sized)
import Test.Ouroboros.Network.TxSubmission.Types
import Test.Ouroboros.Network.Utils
tests :: TestTree
tests :: TestTree
tests = TestName -> [TestTree] -> TestTree
testGroup TestName
"AppV1"
[ TestName -> Property -> TestTree
forall a. Testable a => TestName -> a -> TestTree
testProperty TestName
"txSubmission" ((ArbTxSubmissionConfigs
-> ArbNumTxsToRequest
-> NonEmptyList (Tx Int)
-> Maybe (Positive SmallDelay)
-> Property)
-> Property
forall prop. Testable prop => prop -> Property
checkCoverage ArbTxSubmissionConfigs
-> ArbNumTxsToRequest
-> NonEmptyList (Tx Int)
-> Maybe (Positive SmallDelay)
-> Property
prop_txSubmission)
, TestName -> (ArbNumTxsToRequest -> Property) -> TestTree
forall a. Testable a => TestName -> a -> TestTree
testProperty TestName
"maxNumTxsToRequest is clamped to the sane range"
ArbNumTxsToRequest -> Property
prop_clampMaxNumTxsToRequest
, TestName -> Property -> TestTree
forall a. Testable a => TestName -> a -> TestTree
testProperty TestName
"maxSaneNumTxsToRequest txs fit within the size limit"
Property
prop_maxSaneNumTxsToRequest_fitsSizeLimit
]
data TestVersion = TestVersion
deriving (TestVersion -> TestVersion -> Bool
(TestVersion -> TestVersion -> Bool)
-> (TestVersion -> TestVersion -> Bool) -> Eq TestVersion
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TestVersion -> TestVersion -> Bool
== :: TestVersion -> TestVersion -> Bool
$c/= :: TestVersion -> TestVersion -> Bool
/= :: TestVersion -> TestVersion -> Bool
Eq, Eq TestVersion
Eq TestVersion =>
(TestVersion -> TestVersion -> Ordering)
-> (TestVersion -> TestVersion -> Bool)
-> (TestVersion -> TestVersion -> Bool)
-> (TestVersion -> TestVersion -> Bool)
-> (TestVersion -> TestVersion -> Bool)
-> (TestVersion -> TestVersion -> TestVersion)
-> (TestVersion -> TestVersion -> TestVersion)
-> Ord TestVersion
TestVersion -> TestVersion -> Bool
TestVersion -> TestVersion -> Ordering
TestVersion -> TestVersion -> TestVersion
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: TestVersion -> TestVersion -> Ordering
compare :: TestVersion -> TestVersion -> Ordering
$c< :: TestVersion -> TestVersion -> Bool
< :: TestVersion -> TestVersion -> Bool
$c<= :: TestVersion -> TestVersion -> Bool
<= :: TestVersion -> TestVersion -> Bool
$c> :: TestVersion -> TestVersion -> Bool
> :: TestVersion -> TestVersion -> Bool
$c>= :: TestVersion -> TestVersion -> Bool
>= :: TestVersion -> TestVersion -> Bool
$cmax :: TestVersion -> TestVersion -> TestVersion
max :: TestVersion -> TestVersion -> TestVersion
$cmin :: TestVersion -> TestVersion -> TestVersion
min :: TestVersion -> TestVersion -> TestVersion
Ord, TestVersion
TestVersion -> TestVersion -> Bounded TestVersion
forall a. a -> a -> Bounded a
$cminBound :: TestVersion
minBound :: TestVersion
$cmaxBound :: TestVersion
maxBound :: TestVersion
Bounded, Int -> TestVersion
TestVersion -> Int
TestVersion -> [TestVersion]
TestVersion -> TestVersion
TestVersion -> TestVersion -> [TestVersion]
TestVersion -> TestVersion -> TestVersion -> [TestVersion]
(TestVersion -> TestVersion)
-> (TestVersion -> TestVersion)
-> (Int -> TestVersion)
-> (TestVersion -> Int)
-> (TestVersion -> [TestVersion])
-> (TestVersion -> TestVersion -> [TestVersion])
-> (TestVersion -> TestVersion -> [TestVersion])
-> (TestVersion -> TestVersion -> TestVersion -> [TestVersion])
-> Enum TestVersion
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: TestVersion -> TestVersion
succ :: TestVersion -> TestVersion
$cpred :: TestVersion -> TestVersion
pred :: TestVersion -> TestVersion
$ctoEnum :: Int -> TestVersion
toEnum :: Int -> TestVersion
$cfromEnum :: TestVersion -> Int
fromEnum :: TestVersion -> Int
$cenumFrom :: TestVersion -> [TestVersion]
enumFrom :: TestVersion -> [TestVersion]
$cenumFromThen :: TestVersion -> TestVersion -> [TestVersion]
enumFromThen :: TestVersion -> TestVersion -> [TestVersion]
$cenumFromTo :: TestVersion -> TestVersion -> [TestVersion]
enumFromTo :: TestVersion -> TestVersion -> [TestVersion]
$cenumFromThenTo :: TestVersion -> TestVersion -> TestVersion -> [TestVersion]
enumFromThenTo :: TestVersion -> TestVersion -> TestVersion -> [TestVersion]
Enum, Int -> TestVersion -> ShowS
[TestVersion] -> ShowS
TestVersion -> TestName
(Int -> TestVersion -> ShowS)
-> (TestVersion -> TestName)
-> ([TestVersion] -> ShowS)
-> Show TestVersion
forall a.
(Int -> a -> ShowS) -> (a -> TestName) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TestVersion -> ShowS
showsPrec :: Int -> TestVersion -> ShowS
$cshow :: TestVersion -> TestName
show :: TestVersion -> TestName
$cshowList :: [TestVersion] -> ShowS
showList :: [TestVersion] -> ShowS
Show)
txSubmissionSimulation
:: forall m txid.
( MonadAsync m
, MonadDelay m
, MonadEvaluate m
, MonadFork m
, MonadMask m
, MonadMVar m
, MonadSay m
, MonadST m
, MonadSTM m
, MonadTime m
, MonadTimer m
, MonadThrow m
, MonadThrow (STM m)
, MonadMonotonicTime m
, Ord txid
, Eq txid
, ShowProxy txid
, NoThunks (Tx txid)
, txid ~ Int
)
=> Tracer m (String, TraceSendRecv (TxSubmission2 txid (Tx txid)))
-> Tracer m OutboundRequest
-> TxSubmissionConfig
-> TxSubmissionConfig
-> NumTxsToReq
-> TxOutboundVersion
-> [Tx txid]
-> Maybe Int
-> DiffTime
-> Maybe DiffTime
-> Maybe DiffTime
-> m ([Tx txid], [Tx txid])
txSubmissionSimulation :: forall (m :: * -> *) txid.
(MonadAsync m, MonadDelay m, MonadEvaluate m, MonadFork m,
MonadMask m, MonadMVar m, MonadSay m, MonadST m, MonadSTM m,
MonadTime m, MonadTimer m, MonadThrow m, MonadThrow (STM m),
MonadMonotonicTime m, Ord txid, Eq txid, ShowProxy txid,
NoThunks (Tx txid), txid ~ Int) =>
Tracer m (TestName, TraceSendRecv (TxSubmission2 txid (Tx txid)))
-> Tracer m OutboundRequest
-> TxSubmissionConfig
-> TxSubmissionConfig
-> NumTxsToReq
-> TxOutboundVersion
-> [Tx txid]
-> Maybe Int
-> DiffTime
-> Maybe DiffTime
-> Maybe DiffTime
-> m ([Tx txid], [Tx txid])
txSubmissionSimulation Tracer m (TestName, TraceSendRecv (TxSubmission2 txid (Tx txid)))
tracer
Tracer m OutboundRequest
requestTracer
TxSubmissionConfig
inboundConfig
TxSubmissionConfig
outboundConfig
NumTxsToReq
maxNumTxsToRequest
TxOutboundVersion
version
[Tx txid]
outboundTxs
Maybe Int
expectedTxs
DiffTime
deadline
Maybe DiffTime
inboundDelay
Maybe DiffTime
outboundDelay = do
controlMessageVar <- ControlMessage -> m (TVar m ControlMessage)
forall a. a -> m (TVar m a)
forall (m :: * -> *) a. MonadSTM m => a -> m (TVar m a)
newTVarIO ControlMessage
Continue
let controlMessageSTM = TVar m ControlMessage -> STM m ControlMessage
forall a. TVar m a -> STM m a
forall (m :: * -> *) a. MonadSTM m => TVar m a -> STM m a
readTVar TVar m ControlMessage
controlMessageVar
inboundMempool <- emptyMempool
duplicateTxIdsVar <- newTVarIO []
outboundMempool <- newMempool outboundTxs
(outboundChannel, inboundChannel) <- createConnectedChannels
outboundAsync <-
async $ runPeerWithLimits
(("OUTBOUND",) `contramap` tracer)
txSubmissionCodec2
(byteLimitsTxSubmission2 (fromIntegral . BSL.length))
timeLimitsTxSubmission2
(maybe id delayChannel outboundDelay outboundChannel)
(txSubmissionClientPeer
(traceOutboundRequests
requestTracer
(maxNumUnacknowledgedTxIds outboundConfig)
(outboundPeer controlMessageSTM outboundMempool)))
inboundAsync <-
async $ runPipelinedPeerWithLimits
(("INBOUND",) `contramap` verboseTracer)
txSubmissionCodec2
(byteLimitsTxSubmission2 (fromIntegral . BSL.length))
timeLimitsTxSubmission2
(maybe id delayChannel inboundDelay inboundChannel)
(txSubmissionServerPeerPipelined (inboundPeer duplicateTxIdsVar inboundMempool))
terminateAsync <-
async $ do
let delivered Int
expected = do
inmp <- Mempool m txid (Tx txid) -> m [Tx txid]
forall (m :: * -> *) txid.
MonadSTM m =>
Mempool m txid (Tx txid) -> m [Tx txid]
readMempool Mempool m txid (Tx txid)
inboundMempool
unless (length inmp >= expected) $
threadDelay 1 >> delivered expected
case expectedTxs of
Maybe Int
Nothing -> DiffTime -> m ()
forall (m :: * -> *). MonadDelay m => DiffTime -> m ()
threadDelay DiffTime
deadline
Just Int
expected -> m (Maybe ()) -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m (Maybe ()) -> m ()) -> m (Maybe ()) -> m ()
forall a b. (a -> b) -> a -> b
$ DiffTime -> m () -> m (Maybe ())
forall a. DiffTime -> m a -> m (Maybe a)
forall (m :: * -> *) a.
MonadTimer m =>
DiffTime -> m a -> m (Maybe a)
timeout DiffTime
deadline (Int -> m ()
delivered Int
expected)
atomically (writeTVar controlMessageVar Terminate)
_ <- waitAnyCancel [ outboundAsync, inboundAsync ]
cancel terminateAsync
inmp <- readMempool inboundMempool
outmp <- readMempool outboundMempool
return (inmp, outmp)
where
outboundPeer :: ControlMessageSTM m
-> Mempool m txid (Tx txid)
-> TxSubmissionClient txid (Tx txid) m ()
outboundPeer :: STM m ControlMessage
-> Mempool m txid (Tx txid)
-> TxSubmissionClient txid (Tx txid) m ()
outboundPeer STM m ControlMessage
controlMessageSTM Mempool m txid (Tx txid)
outboundMempool =
Tracer m (TraceTxSubmissionOutbound txid (Tx txid))
-> TxSubmissionConfig
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
-> TxOutboundVersion
-> STM m ControlMessage
-> TxSubmissionClient txid (Tx txid) m ()
forall txid tx idx (m :: * -> *).
(Ord txid, Show txid, Ord idx, MonadSTM m, MonadThrow m) =>
Tracer m (TraceTxSubmissionOutbound txid tx)
-> TxSubmissionConfig
-> TxSubmissionMempoolReader txid tx idx m
-> TxOutboundVersion
-> ControlMessageSTM m
-> TxSubmissionClient txid tx m ()
txSubmissionOutbound
Tracer m (TraceTxSubmissionOutbound txid (Tx txid))
forall (m :: * -> *) a. Monad m => Tracer m a
nullTracer
TxSubmissionConfig
outboundConfig
(Mempool m txid (Tx txid)
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
forall txid (m :: * -> *).
(MonadSTM m, Ord txid, Show txid) =>
Mempool m txid (Tx txid)
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
getMempoolReader Mempool m txid (Tx txid)
outboundMempool)
TxOutboundVersion
version
STM m ControlMessage
controlMessageSTM
inboundPeer :: TVar m [txid]
-> Mempool m txid (Tx txid)
-> TxSubmissionServerPipelined txid (Tx txid) m ()
inboundPeer :: TVar m [txid]
-> Mempool m txid (Tx txid)
-> TxSubmissionServerPipelined txid (Tx txid) m ()
inboundPeer TVar m [txid]
duplicateTxIdsVar Mempool m txid (Tx txid)
inboundMempool =
Tracer m (TraceTxSubmissionInbound txid (Tx txid))
-> TxSubmissionInitDelay
-> TxSubmissionConfig
-> NumTxsToReq
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
-> TxSubmissionMempoolWriter txid (Tx txid) Integer m InvalidTx
-> TxSubmissionServerPipelined txid (Tx txid) m ()
forall txid tx idx (m :: * -> *) err.
(Ord txid, NoThunks txid, NoThunks tx, MonadSTM m, MonadThrow m,
MonadDelay m) =>
Tracer m (TraceTxSubmissionInbound txid tx)
-> TxSubmissionInitDelay
-> TxSubmissionConfig
-> NumTxsToReq
-> TxSubmissionMempoolReader txid tx idx m
-> TxSubmissionMempoolWriter txid tx idx m err
-> TxSubmissionServerPipelined txid tx m ()
txSubmissionInbound
((TestName
"INBOUND",) (TraceTxSubmissionInbound txid (Tx txid)
-> (TestName, TraceTxSubmissionInbound txid (Tx txid)))
-> Tracer m (TestName, TraceTxSubmissionInbound txid (Tx txid))
-> Tracer m (TraceTxSubmissionInbound txid (Tx txid))
forall a' a. (a' -> a) -> Tracer m a -> Tracer m a'
forall (f :: * -> *) a' a.
Contravariant f =>
(a' -> a) -> f a -> f a'
`contramap` Tracer m (TestName, TraceTxSubmissionInbound txid (Tx txid))
forall a (m :: * -> *).
(MonadFork m, MonadDelay m, MonadSay m, MonadMonotonicTime m,
Show a) =>
Tracer m a
verboseTracer)
TxSubmissionInitDelay
NoTxSubmissionInitDelay
TxSubmissionConfig
inboundConfig
NumTxsToReq
maxNumTxsToRequest
(Mempool m txid (Tx txid)
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
forall txid (m :: * -> *).
(MonadSTM m, Ord txid, Show txid) =>
Mempool m txid (Tx txid)
-> TxSubmissionMempoolReader txid (Tx txid) Integer m
getMempoolReader Mempool m txid (Tx txid)
inboundMempool)
(TVar m [txid]
-> Mempool m txid (Tx txid)
-> TxSubmissionMempoolWriter txid (Tx txid) Integer m InvalidTx
forall txid (m :: * -> *).
(MonadSTM m, MonadTime m, MonadThrow m, Ord txid, Eq txid,
Typeable txid, Show txid) =>
TVar m [txid]
-> Mempool m txid (Tx txid)
-> TxSubmissionMempoolWriter txid (Tx txid) Integer m InvalidTx
getMempoolWriter TVar m [txid]
duplicateTxIdsVar Mempool m txid (Tx txid)
inboundMempool)
prop_txSubmission :: ArbTxSubmissionConfigs
-> ArbNumTxsToRequest
-> NonEmptyList (Tx Int)
-> Maybe (Positive SmallDelay)
-> Property
prop_txSubmission :: ArbTxSubmissionConfigs
-> ArbNumTxsToRequest
-> NonEmptyList (Tx Int)
-> Maybe (Positive SmallDelay)
-> Property
prop_txSubmission
(ArbTxSubmissionConfigs TxOutboundVersion
version TxSubmissionConfig
inboundConfig TxSubmissionConfig
outboundConfig)
(ArbNumTxsToRequest NumTxsToReq
maxNumTxsToRequest)
(NonEmpty [Tx Int]
outboundTxs)
Maybe (Positive SmallDelay)
delay
=
let mbDelayTime :: Maybe DiffTime
mbDelayTime = SmallDelay -> DiffTime
getSmallDelay (SmallDelay -> DiffTime)
-> (Positive SmallDelay -> SmallDelay)
-> Positive SmallDelay
-> DiffTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Positive SmallDelay -> SmallDelay
forall a. Positive a -> a
getPositive (Positive SmallDelay -> DiffTime)
-> Maybe (Positive SmallDelay) -> Maybe DiffTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe (Positive SmallDelay)
delay
outUniqueTxIds :: [Tx Int]
outUniqueTxIds = (Tx Int -> Tx Int -> Bool) -> [Tx Int] -> [Tx Int]
forall a. (a -> a -> Bool) -> [a] -> [a]
nubBy ((Int -> Int -> Bool) -> (Tx Int -> Int) -> Tx Int -> Tx Int -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==) Tx Int -> Int
forall txid. Tx txid -> txid
getTxId) [Tx Int]
outboundTxs
outValidTxs :: [Tx Int]
outValidTxs = (Tx Int -> Bool) -> [Tx Int] -> [Tx Int]
forall a. (a -> Bool) -> [a] -> [a]
filter Tx Int -> Bool
forall txid. Tx txid -> Bool
getTxValid [Tx Int]
outboundTxs
uniqueTxIds :: Bool
uniqueTxIds = [Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outUniqueTxIds Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outboundTxs
expectedTxs :: Maybe Int
expectedTxs | Bool
uniqueTxIds = Int -> Maybe Int
forall a. a -> Maybe a
Just ([Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outValidTxs)
| Bool
otherwise = Maybe Int
forall a. Maybe a
Nothing
deadline :: DiffTime
deadline = DiffTime
60 DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
+ DiffTime
20 DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
* DiffTime -> Maybe DiffTime -> DiffTime
forall a. a -> Maybe a -> a
fromMaybe DiffTime
1 Maybe DiffTime
mbDelayTime
DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
* Int -> DiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac ([Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outboundTxs)
tr :: SimTrace ([Tx Int], [Tx Int])
tr = (forall s. IOSim s ([Tx Int], [Tx Int]))
-> SimTrace ([Tx Int], [Tx Int])
forall a. (forall s. IOSim s a) -> SimTrace a
runSimTrace ((forall s. IOSim s ([Tx Int], [Tx Int]))
-> SimTrace ([Tx Int], [Tx Int]))
-> (forall s. IOSim s ([Tx Int], [Tx Int]))
-> SimTrace ([Tx Int], [Tx Int])
forall a b. (a -> b) -> a -> b
$
Tracer
(IOSim s) (TestName, TraceSendRecv (TxSubmission2 Int (Tx Int)))
-> Tracer (IOSim s) OutboundRequest
-> TxSubmissionConfig
-> TxSubmissionConfig
-> NumTxsToReq
-> TxOutboundVersion
-> [Tx Int]
-> Maybe Int
-> DiffTime
-> Maybe DiffTime
-> Maybe DiffTime
-> IOSim s ([Tx Int], [Tx Int])
forall (m :: * -> *) txid.
(MonadAsync m, MonadDelay m, MonadEvaluate m, MonadFork m,
MonadMask m, MonadMVar m, MonadSay m, MonadST m, MonadSTM m,
MonadTime m, MonadTimer m, MonadThrow m, MonadThrow (STM m),
MonadMonotonicTime m, Ord txid, Eq txid, ShowProxy txid,
NoThunks (Tx txid), txid ~ Int) =>
Tracer m (TestName, TraceSendRecv (TxSubmission2 txid (Tx txid)))
-> Tracer m OutboundRequest
-> TxSubmissionConfig
-> TxSubmissionConfig
-> NumTxsToReq
-> TxOutboundVersion
-> [Tx txid]
-> Maybe Int
-> DiffTime
-> Maybe DiffTime
-> Maybe DiffTime
-> m ([Tx txid], [Tx txid])
txSubmissionSimulation
Tracer
(IOSim s) (TestName, TraceSendRecv (TxSubmission2 Int (Tx Int)))
forall a (m :: * -> *).
(MonadFork m, MonadDelay m, MonadSay m, MonadMonotonicTime m,
Show a) =>
Tracer m a
verboseTracer
Tracer (IOSim s) OutboundRequest
forall a s. Typeable a => Tracer (IOSim s) a
dynamicTracer
TxSubmissionConfig
inboundConfig
TxSubmissionConfig
outboundConfig
NumTxsToReq
maxNumTxsToRequest
TxOutboundVersion
version
[Tx Int]
outboundTxs
Maybe Int
expectedTxs
DiffTime
deadline
Maybe DiffTime
mbDelayTime
Maybe DiffTime
mbDelayTime
events :: [RequestTxIdsEvent]
events = [OutboundRequest] -> [RequestTxIdsEvent]
requestTxIdsEvents (SimTrace ([Tx Int], [Tx Int]) -> [OutboundRequest]
forall a b. Typeable b => Trace a SimEvent -> [b]
selectTraceEventsDynamic' SimTrace ([Tx Int], [Tx Int])
tr)
inboundWindow :: NumTxIdsToAck
inboundWindow = TxSubmissionConfig -> NumTxIdsToAck
maxNumUnacknowledgedTxIds TxSubmissionConfig
inboundConfig
outboundWindow :: NumTxIdsToAck
outboundWindow = TxSubmissionConfig -> NumTxIdsToAck
maxNumUnacknowledgedTxIds TxSubmissionConfig
outboundConfig
in
TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
label (TxOutboundVersion -> TestName
forall a. Show a => a -> TestName
show TxOutboundVersion
version) (Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$
Bool -> TestName -> Property -> Property
forall prop. Testable prop => Bool -> TestName -> prop -> Property
classify (NumTxIdsToAck
outboundWindow NumTxIdsToAck -> NumTxIdsToAck -> Bool
forall a. Ord a => a -> a -> Bool
< NumTxIdsToAck
inboundWindow) TestName
"smaller outbound window" (Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$
IO Property -> Property
forall prop. Testable prop => IO prop -> Property
ioProperty (IO Property -> Property) -> IO Property -> Property
forall a b. (a -> b) -> a -> b
$ do
tr' <- SimTrace ([Tx Int], [Tx Int])
-> IO (SimResults ([Tx Int], [Tx Int]))
forall a. SimTrace a -> IO (SimResults a)
evaluateTrace SimTrace ([Tx Int], [Tx Int])
tr
case tr' of
SimException SomeException
e [TestName]
trace -> do
Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ TestName -> Bool -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName -> [TestName] -> TestName
forall a. [a] -> [[a]] -> [a]
intercalate TestName
"\n" ([TestName] -> TestName) -> [TestName] -> TestName
forall a b. (a -> b) -> a -> b
$ SomeException -> TestName
forall a. Show a => a -> TestName
show SomeException
e TestName -> [TestName] -> [TestName]
forall a. a -> [a] -> [a]
: [TestName]
trace) Bool
False
SimDeadLock [TestName]
trace -> do
Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ TestName -> Bool -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName -> [TestName] -> TestName
forall a. [a] -> [[a]] -> [a]
intercalate TestName
"\n" ([TestName] -> TestName) -> [TestName] -> TestName
forall a b. (a -> b) -> a -> b
$ TestName
"Deadlock" TestName -> [TestName] -> [TestName]
forall a. a -> [a] -> [a]
: [TestName]
trace) Bool
False
SimReturn ([Tx Int]
inmp, [Tx Int]
outmp) [TestName]
trace -> do
(Property -> Property) -> IO Property -> IO Property
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ( TestName -> [TestName] -> Property -> Property
forall prop.
Testable prop =>
TestName -> [TestName] -> prop -> Property
tabulate TestName
"MsgRequestTxIds" (RequestTxIdsEvent -> TestName
forall a. Show a => a -> TestName
show (RequestTxIdsEvent -> TestName)
-> [RequestTxIdsEvent] -> [TestName]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [RequestTxIdsEvent]
events)
(Property -> Property)
-> (Property -> Property) -> Property -> Property
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Bool -> TestName -> Property -> Property
forall prop.
Testable prop =>
Double -> Bool -> TestName -> prop -> Property
cover Double
10 (RequestTxIdsEvent
Clamped RequestTxIdsEvent -> [RequestTxIdsEvent] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [RequestTxIdsEvent]
events) TestName
"clamped"
(Property -> Property)
-> (Property -> Property) -> Property -> Property
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Bool -> TestName -> Property -> Property
forall prop.
Testable prop =>
Double -> Bool -> TestName -> prop -> Property
cover Double
10 (RequestTxIdsEvent
ClampedToZero RequestTxIdsEvent -> [RequestTxIdsEvent] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [RequestTxIdsEvent]
events) TestName
"clamped to zero"
) (IO Property -> IO Property) -> IO Property -> IO Property
forall a b. (a -> b) -> a -> b
$
case (Bool
uniqueTxIds, [Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outValidTxs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
outmp) of
a :: (Bool, Bool)
a@(Bool
True, Bool
True) ->
Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName -> [TestName] -> TestName
forall a. [a] -> [[a]] -> [a]
intercalate TestName
"\n" [TestName]
trace)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample ((Bool, Bool) -> TestName
forall a. Show a => a -> TestName
show (Bool, Bool)
a)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ [Tx Int]
inmp [Tx Int] -> [Tx Int] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== [Tx Int]
outValidTxs
a :: (Bool, Bool)
a@(Bool
True, Bool
False) ->
Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName -> [TestName] -> TestName
forall a. [a] -> [[a]] -> [a]
intercalate TestName
"\n" [TestName]
trace)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample ((Bool, Bool) -> TestName
forall a. Show a => a -> TestName
show (Bool, Bool)
a)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ [Tx Int]
inmp [Tx Int] -> [Tx Int] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== [Tx Int]
outValidTxs
a :: (Bool, Bool)
a@(Bool
False, Bool
True) ->
Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName -> [TestName] -> TestName
forall a. [a] -> [[a]] -> [a]
intercalate TestName
"\n" [TestName]
trace)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample ((Bool, Bool) -> TestName
forall a. Show a => a -> TestName
show (Bool, Bool)
a)
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (([Tx Int], [Tx Int]) -> TestName
forall a. Show a => a -> TestName
show ([Tx Int]
inmp, [Tx Int]
outmp))
(Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$ (Tx Int -> Int) -> [Tx Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Tx Int -> Int
forall txid. Tx txid -> txid
getTxId [Tx Int]
inmp [Int] -> [Int] -> Property
forall a. (Eq a, Show a) => a -> a -> Property
=== Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
take ([Tx Int] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Tx Int]
inmp)
((Tx Int -> Int) -> [Tx Int] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map Tx Int -> Int
forall txid. Tx txid -> txid
getTxId ([Tx Int] -> [Int]) -> [Tx Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ (Tx Int -> Bool) -> [Tx Int] -> [Tx Int]
forall a. (a -> Bool) -> [a] -> [a]
filter Tx Int -> Bool
forall txid. Tx txid -> Bool
getTxValid [Tx Int]
outUniqueTxIds)
(Bool
False, Bool
False)
-> Property -> IO Property
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Property -> IO Property) -> Property -> IO Property
forall a b. (a -> b) -> a -> b
$ Bool -> Property
forall prop. Testable prop => prop -> Property
property Bool
True
newtype ArbNumTxsToRequest = ArbNumTxsToRequest NumTxsToReq
deriving Int -> ArbNumTxsToRequest -> ShowS
[ArbNumTxsToRequest] -> ShowS
ArbNumTxsToRequest -> TestName
(Int -> ArbNumTxsToRequest -> ShowS)
-> (ArbNumTxsToRequest -> TestName)
-> ([ArbNumTxsToRequest] -> ShowS)
-> Show ArbNumTxsToRequest
forall a.
(Int -> a -> ShowS) -> (a -> TestName) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ArbNumTxsToRequest -> ShowS
showsPrec :: Int -> ArbNumTxsToRequest -> ShowS
$cshow :: ArbNumTxsToRequest -> TestName
show :: ArbNumTxsToRequest -> TestName
$cshowList :: [ArbNumTxsToRequest] -> ShowS
showList :: [ArbNumTxsToRequest] -> ShowS
Show
instance Arbitrary ArbNumTxsToRequest where
arbitrary :: Gen ArbNumTxsToRequest
arbitrary = NumTxsToReq -> ArbNumTxsToRequest
ArbNumTxsToRequest (NumTxsToReq -> ArbNumTxsToRequest)
-> (Word16 -> NumTxsToReq) -> Word16 -> ArbNumTxsToRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> NumTxsToReq
NumTxsToReq (Word16 -> ArbNumTxsToRequest)
-> Gen Word16 -> Gen ArbNumTxsToRequest
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Int, Gen Word16)] -> Gen Word16
forall a. HasCallStack => [(Int, Gen a)] -> Gen a
frequency
[ (Int
3, Word16 -> Gen Word16
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NumTxsToReq -> Word16
getNumTxsToReq NumTxsToReq
defaultMaxNumTxsToRequest))
, (Int
1, Word16 -> Gen Word16
forall a. a -> Gen a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Word16
0)
, (Int
2, (Word16, Word16) -> Gen Word16
forall a. Random a => (a, a) -> Gen a
choose (Word16
1, NumTxsToReq -> Word16
getNumTxsToReq NumTxsToReq
maxSaneNumTxsToRequest))
, (Int
1, (Word16, Word16) -> Gen Word16
forall a. Random a => (a, a) -> Gen a
choose (NumTxsToReq -> Word16
getNumTxsToReq NumTxsToReq
maxSaneNumTxsToRequest Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ Word16
1, Word16
forall a. Bounded a => a
maxBound))
]
shrink :: ArbNumTxsToRequest -> [ArbNumTxsToRequest]
shrink (ArbNumTxsToRequest (NumTxsToReq Word16
n)) =
NumTxsToReq -> ArbNumTxsToRequest
ArbNumTxsToRequest (NumTxsToReq -> ArbNumTxsToRequest)
-> (Word16 -> NumTxsToReq) -> Word16 -> ArbNumTxsToRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word16 -> NumTxsToReq
NumTxsToReq (Word16 -> ArbNumTxsToRequest) -> [Word16] -> [ArbNumTxsToRequest]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Word16 -> [Word16]
forall a. Arbitrary a => a -> [a]
shrink Word16
n
prop_clampMaxNumTxsToRequest :: ArbNumTxsToRequest -> Property
prop_clampMaxNumTxsToRequest :: ArbNumTxsToRequest -> Property
prop_clampMaxNumTxsToRequest (ArbNumTxsToRequest NumTxsToReq
n) =
let sane :: Bool
sane = NumTxsToReq -> Bool
saneMaxNumTxsToRequest NumTxsToReq
n
in Bool -> TestName -> Property -> Property
forall prop. Testable prop => Bool -> TestName -> prop -> Property
classify Bool
sane TestName
"sane" (Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$
TestName -> Property -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (NumTxsToReq -> TestName
forall a. Show a => a -> TestName
show (NumTxsToReq -> NumTxsToReq
clampMaxNumTxsToRequest NumTxsToReq
n)) (Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$
NumTxsToReq -> Bool
saneMaxNumTxsToRequest (NumTxsToReq -> NumTxsToReq
clampMaxNumTxsToRequest NumTxsToReq
n)
Bool -> Bool -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. (Bool -> Bool
not Bool
sane Bool -> Bool -> Bool
|| NumTxsToReq -> NumTxsToReq
clampMaxNumTxsToRequest NumTxsToReq
n NumTxsToReq -> NumTxsToReq -> Bool
forall a. Eq a => a -> a -> Bool
== NumTxsToReq
n)
prop_maxSaneNumTxsToRequest_fitsSizeLimit :: Property
prop_maxSaneNumTxsToRequest_fitsSizeLimit :: Property
prop_maxSaneNumTxsToRequest_fitsSizeLimit =
Property -> Property
forall prop. Testable prop => prop -> Property
once (Property -> Property) -> Property -> Property
forall a b. (a -> b) -> a -> b
$
TestName -> Bool -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName
"reply with " TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> TestName
forall a. Show a => a -> TestName
show Int
n TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ TestName
" txs: " TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> TestName
forall a. Show a => a -> TestName
show (Int -> Integer
replySize Int
n))
(Int -> Integer
replySize Int
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
limit)
Property -> Property -> Property
forall prop1 prop2.
(Testable prop1, Testable prop2) =>
prop1 -> prop2 -> Property
.&&. TestName -> Bool -> Property
forall prop. Testable prop => TestName -> prop -> Property
counterexample (TestName
"reply with " TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> TestName
forall a. Show a => a -> TestName
show (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ TestName
" txs: " TestName -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> TestName
forall a. Show a => a -> TestName
show (Int -> Integer
replySize (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)))
(Int -> Integer
replySize (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
limit)
where
n :: Int
n :: Int
n = NumTxsToReq -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral NumTxsToReq
maxSaneNumTxsToRequest
tx :: SizedBytes
tx :: SizedBytes
tx = Word -> SizedBytes
SizedBytes (SizeInBytes -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (SizeInBytes
max_TX_SIZE SizeInBytes -> SizeInBytes -> SizeInBytes
forall a. Num a => a -> a -> a
+ SizeInBytes
const_MAX_TX_SIZE_DISCREPANCY))
replySize :: Int -> Integer
replySize :: Int -> Integer
replySize Int
k =
Int64 -> Integer
forall a. Integral a => a -> Integer
toInteger (Int64 -> Integer)
-> (Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> Int64)
-> Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Int64
BSL.length (ByteString -> Int64)
-> (Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> ByteString)
-> Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> Int64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CodecF
(TxSubmission2 SizedBytes SizedBytes)
DeserialiseFailure
IO
SomeMessage
ByteString
-> forall (st :: TxSubmission2 SizedBytes SizedBytes)
(st' :: TxSubmission2 SizedBytes SizedBytes).
(StateTokenI st, ActiveState st) =>
Message (TxSubmission2 SizedBytes SizedBytes) st st' -> ByteString
forall ps failure (m :: * -> *) (f :: ps -> *) bytes.
CodecF ps failure m f bytes
-> forall (st :: ps) (st' :: ps).
(StateTokenI st, ActiveState st) =>
Message ps st st' -> bytes
encode (forall (m :: * -> *).
MonadST m =>
Codec
(TxSubmission2 SizedBytes SizedBytes)
DeserialiseFailure
m
ByteString
codec_sized @IO)
(Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> Integer)
-> Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
-> Integer
forall a b. (a -> b) -> a -> b
$ ([SizedBytes]
-> Message (TxSubmission2 SizedBytes SizedBytes) 'StTxs 'StIdle
forall tx txid.
[tx] -> Message (TxSubmission2 txid tx) 'StTxs 'StIdle
MsgReplyTxs (Int -> SizedBytes -> [SizedBytes]
forall a. Int -> a -> [a]
replicate Int
k SizedBytes
tx)
:: Message (TxSubmission2 SizedBytes SizedBytes) StTxs StIdle)
limit :: Integer
limit :: Integer
limit = Word -> Integer
forall a. Integral a => a -> Integer
toInteger
(Word -> Integer) -> Word -> Integer
forall a b. (a -> b) -> a -> b
$ ProtocolSizeLimits
(TxSubmission2 (ZonkAny 0) (ZonkAny 1)) (ZonkAny 2)
-> forall (st :: TxSubmission2 (ZonkAny 0) (ZonkAny 1)).
ActiveState st =>
StateToken st -> Word
forall ps bytes.
ProtocolSizeLimits ps bytes
-> forall (st :: ps). ActiveState st => StateToken st -> Word
sizeLimitForState ((ZonkAny 2 -> Word)
-> ProtocolSizeLimits
(TxSubmission2 (ZonkAny 0) (ZonkAny 1)) (ZonkAny 2)
forall bytes txid tx.
(bytes -> Word) -> ProtocolSizeLimits (TxSubmission2 txid tx) bytes
byteLimitsTxSubmission2 (TestName -> ZonkAny 2 -> Word
forall a. HasCallStack => TestName -> a
error TestName
"unused")) StateToken 'StTxs
SingTxSubmission 'StTxs
forall {txid} {tx}. SingTxSubmission 'StTxs
SingTxs