{-|
Module      : Haskoin.Test.Network
Copyright   : No rights reserved
License     : MIT
Maintainer  : jprupp@protonmail.ch
Stability   : experimental
Portability : POSIX
-}
module Haskoin.Util.Arbitrary.Network where

import qualified Data.ByteString               as BS (empty, pack)
import qualified Data.ByteString.Char8         as C8
import           Data.Word                     (Word16, Word32)
import           Haskoin.Network
import           Haskoin.Util.Arbitrary.Crypto
import           Haskoin.Util.Arbitrary.Util
import           Network.Socket                (SockAddr (..))
import           Test.QuickCheck

-- | Arbitrary 'VarInt'.
arbitraryVarInt :: Gen VarInt
arbitraryVarInt :: Gen VarInt
arbitraryVarInt = Word64 -> VarInt
VarInt (Word64 -> VarInt) -> Gen Word64 -> Gen VarInt
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary 'VarString'.
arbitraryVarString :: Gen VarString
arbitraryVarString :: Gen VarString
arbitraryVarString = ByteString -> VarString
VarString (ByteString -> VarString) -> Gen ByteString -> Gen VarString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen ByteString
arbitraryBS

-- | Arbitrary 'NetworkAddress'.
arbitraryNetworkAddress :: Gen NetworkAddress
arbitraryNetworkAddress :: Gen NetworkAddress
arbitraryNetworkAddress = do
    Word64
s <- Gen Word64
forall a. Arbitrary a => Gen a
arbitrary
    Word32
a <- Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
    Word16
p <- Gen Word16
forall a. Arbitrary a => Gen a
arbitrary
    SockAddr
d <- [Gen SockAddr] -> Gen SockAddr
forall a. [Gen a] -> Gen a
oneof
        [ do
            Word32
b <- Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
            Word32
c <- Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
            Word32
d <- Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
            SockAddr -> Gen SockAddr
forall (m :: * -> *) a. Monad m => a -> m a
return (SockAddr -> Gen SockAddr) -> SockAddr -> Gen SockAddr
forall a b. (a -> b) -> a -> b
$ PortNumber -> Word32 -> HostAddress6 -> Word32 -> SockAddr
SockAddrInet6 (Word16 -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
p) 0 (Word32
a,Word32
b,Word32
c,Word32
d) 0
        , SockAddr -> Gen SockAddr
forall (m :: * -> *) a. Monad m => a -> m a
return (SockAddr -> Gen SockAddr) -> SockAddr -> Gen SockAddr
forall a b. (a -> b) -> a -> b
$ PortNumber -> Word32 -> SockAddr
SockAddrInet (Word16 -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16
p :: Word16)) Word32
a
        ]
    let n :: HostAddress
n = SockAddr -> HostAddress
sockToHostAddress SockAddr
d
    NetworkAddress -> Gen NetworkAddress
forall (m :: * -> *) a. Monad m => a -> m a
return (NetworkAddress -> Gen NetworkAddress)
-> NetworkAddress -> Gen NetworkAddress
forall a b. (a -> b) -> a -> b
$ Word64 -> HostAddress -> NetworkAddress
NetworkAddress Word64
s HostAddress
n

-- | Arbitrary 'NetworkAddressTime'.
arbitraryNetworkAddressTime :: Gen (Word32, NetworkAddress)
arbitraryNetworkAddressTime :: Gen (Word32, NetworkAddress)
arbitraryNetworkAddressTime = (,) (Word32 -> NetworkAddress -> (Word32, NetworkAddress))
-> Gen Word32 -> Gen (NetworkAddress -> (Word32, NetworkAddress))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary Gen (NetworkAddress -> (Word32, NetworkAddress))
-> Gen NetworkAddress -> Gen (Word32, NetworkAddress)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen NetworkAddress
arbitraryNetworkAddress

-- | Arbitrary 'InvType'.
arbitraryInvType :: Gen InvType
arbitraryInvType :: Gen InvType
arbitraryInvType = [InvType] -> Gen InvType
forall a. [a] -> Gen a
elements [InvType
InvError, InvType
InvTx, InvType
InvBlock, InvType
InvMerkleBlock]

-- | Arbitrary 'InvVector'.
arbitraryInvVector :: Gen InvVector
arbitraryInvVector :: Gen InvVector
arbitraryInvVector = InvType -> Hash256 -> InvVector
InvVector (InvType -> Hash256 -> InvVector)
-> Gen InvType -> Gen (Hash256 -> InvVector)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen InvType
arbitraryInvType Gen (Hash256 -> InvVector) -> Gen Hash256 -> Gen InvVector
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Hash256
arbitraryHash256

-- | Arbitrary non-empty 'Inv'.
arbitraryInv1 :: Gen Inv
arbitraryInv1 :: Gen Inv
arbitraryInv1 = [InvVector] -> Inv
Inv ([InvVector] -> Inv) -> Gen [InvVector] -> Gen Inv
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen InvVector -> Gen [InvVector]
forall a. Gen a -> Gen [a]
listOf1 Gen InvVector
arbitraryInvVector

-- | Arbitrary 'Version'.
arbitraryVersion :: Gen Version
arbitraryVersion :: Gen Version
arbitraryVersion =
    Word32
-> Word64
-> Word64
-> NetworkAddress
-> NetworkAddress
-> Word64
-> VarString
-> Word32
-> Bool
-> Version
Version (Word32
 -> Word64
 -> Word64
 -> NetworkAddress
 -> NetworkAddress
 -> Word64
 -> VarString
 -> Word32
 -> Bool
 -> Version)
-> Gen Word32
-> Gen
     (Word64
      -> Word64
      -> NetworkAddress
      -> NetworkAddress
      -> Word64
      -> VarString
      -> Word32
      -> Bool
      -> Version)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
            Gen
  (Word64
   -> Word64
   -> NetworkAddress
   -> NetworkAddress
   -> Word64
   -> VarString
   -> Word32
   -> Bool
   -> Version)
-> Gen Word64
-> Gen
     (Word64
      -> NetworkAddress
      -> NetworkAddress
      -> Word64
      -> VarString
      -> Word32
      -> Bool
      -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary
            Gen
  (Word64
   -> NetworkAddress
   -> NetworkAddress
   -> Word64
   -> VarString
   -> Word32
   -> Bool
   -> Version)
-> Gen Word64
-> Gen
     (NetworkAddress
      -> NetworkAddress
      -> Word64
      -> VarString
      -> Word32
      -> Bool
      -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary
            Gen
  (NetworkAddress
   -> NetworkAddress
   -> Word64
   -> VarString
   -> Word32
   -> Bool
   -> Version)
-> Gen NetworkAddress
-> Gen
     (NetworkAddress
      -> Word64 -> VarString -> Word32 -> Bool -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen NetworkAddress
arbitraryNetworkAddress
            Gen
  (NetworkAddress
   -> Word64 -> VarString -> Word32 -> Bool -> Version)
-> Gen NetworkAddress
-> Gen (Word64 -> VarString -> Word32 -> Bool -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen NetworkAddress
arbitraryNetworkAddress
            Gen (Word64 -> VarString -> Word32 -> Bool -> Version)
-> Gen Word64 -> Gen (VarString -> Word32 -> Bool -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary
            Gen (VarString -> Word32 -> Bool -> Version)
-> Gen VarString -> Gen (Word32 -> Bool -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen VarString
arbitraryVarString
            Gen (Word32 -> Bool -> Version)
-> Gen Word32 -> Gen (Bool -> Version)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
            Gen (Bool -> Version) -> Gen Bool -> Gen Version
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen Bool
forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary non-empty 'Addr'.
arbitraryAddr1 :: Gen Addr
arbitraryAddr1 :: Gen Addr
arbitraryAddr1 = [(Word32, NetworkAddress)] -> Addr
Addr ([(Word32, NetworkAddress)] -> Addr)
-> Gen [(Word32, NetworkAddress)] -> Gen Addr
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen (Word32, NetworkAddress) -> Gen [(Word32, NetworkAddress)]
forall a. Gen a -> Gen [a]
listOf1 Gen (Word32, NetworkAddress)
arbitraryNetworkAddressTime

-- | Arbitrary 'Alert' with random payload and signature. Signature is not
-- valid.
arbitraryAlert :: Gen Alert
arbitraryAlert :: Gen Alert
arbitraryAlert = VarString -> VarString -> Alert
Alert (VarString -> VarString -> Alert)
-> Gen VarString -> Gen (VarString -> Alert)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen VarString
arbitraryVarString Gen (VarString -> Alert) -> Gen VarString -> Gen Alert
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Gen VarString
arbitraryVarString

-- | Arbitrary 'Reject'.
arbitraryReject :: Gen Reject
arbitraryReject :: Gen Reject
arbitraryReject = do
    MessageCommand
m <- Gen MessageCommand
arbitraryMessageCommand
    RejectCode
c <- Gen RejectCode
arbitraryRejectCode
    VarString
s <- Gen VarString
arbitraryVarString
    ByteString
d <- [Gen ByteString] -> Gen ByteString
forall a. [Gen a] -> Gen a
oneof [ ByteString -> Gen ByteString
forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
BS.empty
               , [Word8] -> ByteString
BS.pack ([Word8] -> ByteString) -> Gen [Word8] -> Gen ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> Gen Word8 -> Gen [Word8]
forall a. Int -> Gen a -> Gen [a]
vectorOf 32 Gen Word8
forall a. Arbitrary a => Gen a
arbitrary
               ]
    Reject -> Gen Reject
forall (m :: * -> *) a. Monad m => a -> m a
return (Reject -> Gen Reject) -> Reject -> Gen Reject
forall a b. (a -> b) -> a -> b
$ MessageCommand -> RejectCode -> VarString -> ByteString -> Reject
Reject MessageCommand
m RejectCode
c VarString
s ByteString
d

-- | Arbitrary 'RejectCode'.
arbitraryRejectCode :: Gen RejectCode
arbitraryRejectCode :: Gen RejectCode
arbitraryRejectCode =
    [RejectCode] -> Gen RejectCode
forall a. [a] -> Gen a
elements
        [ RejectCode
RejectMalformed
        , RejectCode
RejectInvalid
        , RejectCode
RejectInvalid
        , RejectCode
RejectDuplicate
        , RejectCode
RejectNonStandard
        , RejectCode
RejectDust
        , RejectCode
RejectInsufficientFee
        , RejectCode
RejectCheckpoint
        ]

-- | Arbitrary non-empty 'GetData'.
arbitraryGetData :: Gen GetData
arbitraryGetData :: Gen GetData
arbitraryGetData = [InvVector] -> GetData
GetData ([InvVector] -> GetData) -> Gen [InvVector] -> Gen GetData
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen InvVector -> Gen [InvVector]
forall a. Gen a -> Gen [a]
listOf1 Gen InvVector
arbitraryInvVector

-- | Arbitrary 'NotFound'.
arbitraryNotFound :: Gen NotFound
arbitraryNotFound :: Gen NotFound
arbitraryNotFound = [InvVector] -> NotFound
NotFound ([InvVector] -> NotFound) -> Gen [InvVector] -> Gen NotFound
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen InvVector -> Gen [InvVector]
forall a. Gen a -> Gen [a]
listOf1 Gen InvVector
arbitraryInvVector

-- | Arbitrary 'Ping'.
arbitraryPing :: Gen Ping
arbitraryPing :: Gen Ping
arbitraryPing = Word64 -> Ping
Ping (Word64 -> Ping) -> Gen Word64 -> Gen Ping
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary 'Pong'.
arbitraryPong :: Gen Pong
arbitraryPong :: Gen Pong
arbitraryPong = Word64 -> Pong
Pong (Word64 -> Pong) -> Gen Word64 -> Gen Pong
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen Word64
forall a. Arbitrary a => Gen a
arbitrary

-- | Arbitrary bloom filter flags.
arbitraryBloomFlags :: Gen BloomFlags
arbitraryBloomFlags :: Gen BloomFlags
arbitraryBloomFlags =
    [BloomFlags] -> Gen BloomFlags
forall a. [a] -> Gen a
elements
        [ BloomFlags
BloomUpdateNone
        , BloomFlags
BloomUpdateAll
        , BloomFlags
BloomUpdateP2PubKeyOnly
        ]

-- | Arbitrary bloom filter with its corresponding number of elements
-- and false positive rate.
arbitraryBloomFilter :: Gen (Int, Double, BloomFilter)
arbitraryBloomFilter :: Gen (Int, Double, BloomFilter)
arbitraryBloomFilter = do
    Int
n     <- (Int, Int) -> Gen Int
forall a. Random a => (a, a) -> Gen a
choose (0,100000)
    Double
fp    <- (Double, Double) -> Gen Double
forall a. Random a => (a, a) -> Gen a
choose (1e-8,1)
    Word32
tweak <- Gen Word32
forall a. Arbitrary a => Gen a
arbitrary
    BloomFlags
fl    <- Gen BloomFlags
arbitraryBloomFlags
    (Int, Double, BloomFilter) -> Gen (Int, Double, BloomFilter)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
n, Double
fp, Int -> Double -> Word32 -> BloomFlags -> BloomFilter
bloomCreate Int
n Double
fp Word32
tweak BloomFlags
fl)

-- | Arbitrary 'FilterLoad'.
arbitraryFilterLoad :: Gen FilterLoad
arbitraryFilterLoad :: Gen FilterLoad
arbitraryFilterLoad = do
    (_, _, bf :: BloomFilter
bf) <- Gen (Int, Double, BloomFilter)
arbitraryBloomFilter
    FilterLoad -> Gen FilterLoad
forall (m :: * -> *) a. Monad m => a -> m a
return (FilterLoad -> Gen FilterLoad) -> FilterLoad -> Gen FilterLoad
forall a b. (a -> b) -> a -> b
$ BloomFilter -> FilterLoad
FilterLoad BloomFilter
bf

-- | Arbitrary 'FilterAdd'.
arbitraryFilterAdd :: Gen FilterAdd
arbitraryFilterAdd :: Gen FilterAdd
arbitraryFilterAdd = ByteString -> FilterAdd
FilterAdd (ByteString -> FilterAdd) -> Gen ByteString -> Gen FilterAdd
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Gen ByteString
arbitraryBS

-- | Arbitrary 'MessageCommand'.
arbitraryMessageCommand :: Gen MessageCommand
arbitraryMessageCommand :: Gen MessageCommand
arbitraryMessageCommand = do
    ASCIIString str :: String
str <- Gen ASCIIString
forall a. Arbitrary a => Gen a
arbitrary
    [MessageCommand] -> Gen MessageCommand
forall a. [a] -> Gen a
elements
        [ MessageCommand
MCVersion
        , MessageCommand
MCVerAck
        , MessageCommand
MCAddr
        , MessageCommand
MCInv
        , MessageCommand
MCGetData
        , MessageCommand
MCNotFound
        , MessageCommand
MCGetBlocks
        , MessageCommand
MCGetHeaders
        , MessageCommand
MCTx
        , MessageCommand
MCBlock
        , MessageCommand
MCMerkleBlock
        , MessageCommand
MCHeaders
        , MessageCommand
MCGetAddr
        , MessageCommand
MCFilterLoad
        , MessageCommand
MCFilterAdd
        , MessageCommand
MCFilterClear
        , MessageCommand
MCPing
        , MessageCommand
MCPong
        , MessageCommand
MCAlert
        , ByteString -> MessageCommand
MCOther (Int -> ByteString -> ByteString
C8.take 12 (String -> ByteString
C8.pack ((Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '\NUL') String
str)))
        ]