-- | Tests for the @?address=@ output filter applied by 'Hydra.API.WSServer'.
-- 'Hydra.API.ServerSpec' covers the server-side wiring that reaches it.
module Hydra.API.ServerOutputFilterSpec where

import Hydra.Prelude
import Test.Hydra.Prelude

import Data.Text qualified as Text
import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
import Hydra.API.ServerOutput (ServerOutput (..), TimedServerOutput (..))
import Hydra.API.ServerOutputFilter (ServerOutputFilter (..), serverOutputFilter)
import Hydra.Cardano.Api
import Hydra.Cardano.Api.Gen (genTxIn)
import Hydra.HeadLogicSpec (testSnapshot)
import Hydra.Ledger.Cardano.Builder (addTxInsSpending, unsafeBuildTransaction)
import Test.Hydra.API.ServerOutput ()
import Test.Hydra.Chain.Direct.State ()
import Test.Hydra.Tx.Fixture (testHeadId, testNetworkId)
import Test.Hydra.Tx.Gen (genKeyPair)
import Test.QuickCheck (generate)
import Test.QuickCheck.Arbitrary.ADT (ADTArbitrary (..), ConstructorArbitraryPair (..), toADTArbitrary)

spec :: Spec
spec :: Spec
spec = Spec -> Spec
forall a. SpecWith a -> SpecWith a
parallel (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"SnapshotConfirmed" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes a snapshot whose confirmed tx pays the address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress]] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"drops a snapshot when no confirmed tx involves the address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
bobAddress]] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldDropFor` AddressInEra
aliceAddress

    -- A snapshot confirming no transaction settles only a deposit or a
    -- decommit. It carries no address, so it is not withheld: the filter
    -- narrows what a client sees rather than hiding addressless events.
    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes a snapshot confirming no transactions" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes when any one of several confirmed txs involves the address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
bobAddress], [AddressInEra] -> Tx
txPayingTo [AddressInEra
carolAddress, AddressInEra
aliceAddress]]
        HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes when the address is any one of a tx's outputs" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
bobAddress, AddressInEra
carolAddress, AddressInEra
aliceAddress]]
        HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

  -- The snapshot in which a client's funds leave the head is the one it most
  -- needs, and a transaction spending a UTxO in full leaves no output to match.
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"spending from the address" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes a snapshot whose confirmed tx spends from the address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [AddressInEra -> Tx
aliceSpendsTo AddressInEra
bobAddress] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"still drops that snapshot for an uninvolved address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [AddressInEra -> Tx
aliceSpendsTo AddressInEra
bobAddress] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldDropFor` AddressInEra
carolAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes for both the sender and the recipient" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$ do
      [Tx] -> ServerOutput Tx
snapshotConfirmed [AddressInEra -> Tx
aliceSpendsTo AddressInEra
bobAddress] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
bobAddress
      [Tx] -> ServerOutput Tx
snapshotConfirmed [AddressInEra -> Tx
aliceSpendsTo AddressInEra
bobAddress] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldPassFor` AddressInEra
aliceAddress

  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"address comparison" (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"does not match a well-formed address that is not involved" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress, AddressInEra
bobAddress]] HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
ServerOutput Tx -> AddressInEra -> Expectation
`shouldDropFor` AddressInEra
carolAddress

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"does not match a string that is not an address" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$ do
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress]] HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
`shouldDrop` Text
"invalid"
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress]] HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
`shouldDrop` Text
""

    String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"does not match an address truncated or extended by one character" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$ do
      let addr :: Text
addr = AddressInEra -> Text
bech32Of AddressInEra
aliceAddress
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress]] HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
`shouldDrop` HasCallStack => Text -> Text
Text -> Text
Text.init Text
addr
      [Tx] -> ServerOutput Tx
snapshotConfirmed [[AddressInEra] -> Tx
txPayingTo [AddressInEra
aliceAddress]] HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
`shouldDrop` (Text
addr Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"x")

  -- Enumerated rather than sampled: adding a filtering arm for any other
  -- output would otherwise go unnoticed. Several of them do carry a
  -- transaction ('TxInvalid', 'DecommitRequested', 'DecommitInvalid'), so
  -- passing them is a decision, not a consequence of having nothing to match.
  String -> Expectation -> SpecM (Arg Expectation) ()
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"passes every output other than SnapshotConfirmed" (Expectation -> SpecM (Arg Expectation) ())
-> Expectation -> SpecM (Arg Expectation) ()
forall a b. (a -> b) -> a -> b
$ do
    [(String, ServerOutput Tx)]
others <- IO [(String, ServerOutput Tx)]
serverOutputsOtherThanSnapshotConfirmed
    [(String, ServerOutput Tx)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(String, ServerOutput Tx)]
others Int -> (Int -> Bool) -> Expectation
forall a. (HasCallStack, Show a) => a -> (a -> Bool) -> Expectation
`shouldSatisfy` (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1)
    [(String, ServerOutput Tx)]
-> ((String, ServerOutput Tx) -> Expectation) -> Expectation
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(String, ServerOutput Tx)]
others (((String, ServerOutput Tx) -> Expectation) -> Expectation)
-> ((String, ServerOutput Tx) -> Expectation) -> Expectation
forall a b. (a -> b) -> a -> b
$ \(String
name, ServerOutput Tx
out) ->
      Bool -> Expectation -> Expectation
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ServerOutput Tx -> Text -> Bool
matches ServerOutput Tx
out (AddressInEra -> Text
bech32Of AddressInEra
carolAddress)) (Expectation -> Expectation)
-> (String -> Expectation) -> String -> Expectation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Expectation
forall (m :: * -> *) a.
(HasCallStack, MonadThrow m) =>
String -> m a
failure (String -> Expectation) -> String -> Expectation
forall a b. (a -> b) -> a -> b
$
        String
name String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" was filtered out"

-- * Fixtures

aliceKeys, bobKeys, carolKeys :: (VerificationKey PaymentKey, SigningKey PaymentKey)
aliceKeys :: (VerificationKey PaymentKey, SigningKey PaymentKey)
aliceKeys = Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
genKeyPair Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
-> Int -> (VerificationKey PaymentKey, SigningKey PaymentKey)
forall a. Gen a -> Int -> a
`generateWith` Int
1
bobKeys :: (VerificationKey PaymentKey, SigningKey PaymentKey)
bobKeys = Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
genKeyPair Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
-> Int -> (VerificationKey PaymentKey, SigningKey PaymentKey)
forall a. Gen a -> Int -> a
`generateWith` Int
2
carolKeys :: (VerificationKey PaymentKey, SigningKey PaymentKey)
carolKeys = Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
genKeyPair Gen (VerificationKey PaymentKey, SigningKey PaymentKey)
-> Int -> (VerificationKey PaymentKey, SigningKey PaymentKey)
forall a. Gen a -> Int -> a
`generateWith` Int
3

aliceAddress, bobAddress, carolAddress :: AddressInEra
aliceAddress :: AddressInEra
aliceAddress = NetworkId -> VerificationKey PaymentKey -> AddressInEra
forall era.
IsShelleyBasedEra era =>
NetworkId -> VerificationKey PaymentKey -> AddressInEra era
mkVkAddress NetworkId
testNetworkId ((VerificationKey PaymentKey, SigningKey PaymentKey)
-> VerificationKey PaymentKey
forall a b. (a, b) -> a
fst (VerificationKey PaymentKey, SigningKey PaymentKey)
aliceKeys)
bobAddress :: AddressInEra
bobAddress = NetworkId -> VerificationKey PaymentKey -> AddressInEra
forall era.
IsShelleyBasedEra era =>
NetworkId -> VerificationKey PaymentKey -> AddressInEra era
mkVkAddress NetworkId
testNetworkId ((VerificationKey PaymentKey, SigningKey PaymentKey)
-> VerificationKey PaymentKey
forall a b. (a, b) -> a
fst (VerificationKey PaymentKey, SigningKey PaymentKey)
bobKeys)
carolAddress :: AddressInEra
carolAddress = NetworkId -> VerificationKey PaymentKey -> AddressInEra
forall era.
IsShelleyBasedEra era =>
NetworkId -> VerificationKey PaymentKey -> AddressInEra era
mkVkAddress NetworkId
testNetworkId ((VerificationKey PaymentKey, SigningKey PaymentKey)
-> VerificationKey PaymentKey
forall a b. (a, b) -> a
fst (VerificationKey PaymentKey, SigningKey PaymentKey)
carolKeys)

-- | A transaction paying 2 Ada to each of the given addresses, unsigned.
txPayingTo :: [AddressInEra] -> Tx
txPayingTo :: [AddressInEra] -> Tx
txPayingTo [AddressInEra]
addresses =
  HasCallStack => TxBodyContent BuildTx -> Tx
TxBodyContent BuildTx -> Tx
unsafeBuildTransaction (TxBodyContent BuildTx -> Tx) -> TxBodyContent BuildTx -> Tx
forall a b. (a -> b) -> a -> b
$
    TxBodyContent BuildTx
defaultTxBodyContent
      TxBodyContent BuildTx
-> (TxBodyContent BuildTx -> TxBodyContent BuildTx)
-> TxBodyContent BuildTx
forall a b. a -> (a -> b) -> b
& [TxIn] -> TxBodyContent BuildTx -> TxBodyContent BuildTx
addTxInsSpending [Gen TxIn
genTxIn Gen TxIn -> Int -> TxIn
forall a. Gen a -> Int -> a
`generateWith` Int
42]
      TxBodyContent BuildTx
-> (TxBodyContent BuildTx -> TxBodyContent BuildTx)
-> TxBodyContent BuildTx
forall a b. a -> (a -> b) -> b
& [TxOut CtxTx Era] -> TxBodyContent BuildTx -> TxBodyContent BuildTx
forall era build.
[TxOut CtxTx era]
-> TxBodyContent build era -> TxBodyContent build era
addTxOuts
        [ AddressInEra
-> Value -> TxOutDatum CtxTx -> ReferenceScript -> TxOut CtxTx Era
forall ctx.
AddressInEra
-> Value -> TxOutDatum ctx -> ReferenceScript -> TxOut ctx
TxOut AddressInEra
address (Lovelace -> Value
lovelaceToValue Lovelace
2_000_000) TxOutDatum CtxTx
forall ctx. TxOutDatum ctx
TxOutDatumNone ReferenceScript
ReferenceScriptNone
        | AddressInEra
address <- [AddressInEra]
addresses
        ]

-- | Signed by Alice and paying only to the given address, so her witness is
-- all the filter has to go on.
aliceSpendsTo :: AddressInEra -> Tx
aliceSpendsTo :: AddressInEra -> Tx
aliceSpendsTo AddressInEra
recipient = SigningKey PaymentKey -> Tx -> Tx
forall era.
IsShelleyBasedEra era =>
SigningKey PaymentKey -> Tx era -> Tx era
signTx ((VerificationKey PaymentKey, SigningKey PaymentKey)
-> SigningKey PaymentKey
forall a b. (a, b) -> b
snd (VerificationKey PaymentKey, SigningKey PaymentKey)
aliceKeys) ([AddressInEra] -> Tx
txPayingTo [AddressInEra
recipient])

snapshotConfirmed :: [Tx] -> ServerOutput Tx
snapshotConfirmed :: [Tx] -> ServerOutput Tx
snapshotConfirmed [Tx]
confirmed =
  SnapshotConfirmed
    { $sel:headId:NetworkConnected :: HeadId
headId = HeadId
testHeadId
    , $sel:snapshot:NetworkConnected :: Snapshot Tx
snapshot = SnapshotNumber
-> SnapshotVersion -> [Tx] -> UTxOType Tx -> Snapshot Tx
forall tx.
IsTx tx =>
SnapshotNumber
-> SnapshotVersion -> [tx] -> UTxOType tx -> Snapshot tx
testSnapshot SnapshotNumber
1 SnapshotVersion
0 [Tx]
confirmed UTxOType Tx
UTxO
forall a. Monoid a => a
mempty
    , $sel:signatures:NetworkConnected :: MultiSignature (Snapshot Tx)
signatures = MultiSignature (Snapshot Tx)
forall a. Monoid a => a
mempty
    }

serverOutputsOtherThanSnapshotConfirmed :: IO [(String, ServerOutput Tx)]
serverOutputsOtherThanSnapshotConfirmed :: IO [(String, ServerOutput Tx)]
serverOutputsOtherThanSnapshotConfirmed = do
  ADTArbitrary{[ConstructorArbitraryPair (ServerOutput Tx)]
adtCAPs :: [ConstructorArbitraryPair (ServerOutput Tx)]
adtCAPs :: forall a. ADTArbitrary a -> [ConstructorArbitraryPair a]
adtCAPs} <- Gen (ADTArbitrary (ServerOutput Tx))
-> IO (ADTArbitrary (ServerOutput Tx))
forall a. Gen a -> IO a
generate (Gen (ADTArbitrary (ServerOutput Tx))
 -> IO (ADTArbitrary (ServerOutput Tx)))
-> Gen (ADTArbitrary (ServerOutput Tx))
-> IO (ADTArbitrary (ServerOutput Tx))
forall a b. (a -> b) -> a -> b
$ Proxy (ServerOutput Tx) -> Gen (ADTArbitrary (ServerOutput Tx))
forall a. ToADTArbitrary a => Proxy a -> Gen (ADTArbitrary a)
toADTArbitrary (forall t. Proxy t
forall {k} (t :: k). Proxy t
Proxy @(ServerOutput Tx))
  [(String, ServerOutput Tx)] -> IO [(String, ServerOutput Tx)]
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    [ (String
capConstructor, ServerOutput Tx
capArbitrary)
    | ConstructorArbitraryPair{String
capConstructor :: String
capConstructor :: forall a. ConstructorArbitraryPair a -> String
capConstructor, ServerOutput Tx
capArbitrary :: ServerOutput Tx
capArbitrary :: forall a. ConstructorArbitraryPair a -> a
capArbitrary} <- [ConstructorArbitraryPair (ServerOutput Tx)]
adtCAPs
    , String
capConstructor String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= String
"SnapshotConfirmed"
    ]

-- * Helpers

shouldPassFor :: HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
shouldPassFor :: HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
shouldPassFor ServerOutput Tx
out = HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
shouldPass ServerOutput Tx
out (Text -> Expectation)
-> (AddressInEra -> Text) -> AddressInEra -> Expectation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddressInEra -> Text
bech32Of

shouldDropFor :: HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
shouldDropFor :: HasCallStack => ServerOutput Tx -> AddressInEra -> Expectation
shouldDropFor ServerOutput Tx
out = HasCallStack => ServerOutput Tx -> Text -> Expectation
ServerOutput Tx -> Text -> Expectation
shouldDrop ServerOutput Tx
out (Text -> Expectation)
-> (AddressInEra -> Text) -> AddressInEra -> Expectation
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AddressInEra -> Text
bech32Of

shouldPass :: HasCallStack => ServerOutput Tx -> Text -> Expectation
shouldPass :: HasCallStack => ServerOutput Tx -> Text -> Expectation
shouldPass ServerOutput Tx
out Text
address = ServerOutput Tx -> Text -> Bool
matches ServerOutput Tx
out Text
address Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` Bool
True

shouldDrop :: HasCallStack => ServerOutput Tx -> Text -> Expectation
shouldDrop :: HasCallStack => ServerOutput Tx -> Text -> Expectation
shouldDrop ServerOutput Tx
out Text
address = ServerOutput Tx -> Text -> Bool
matches ServerOutput Tx
out Text
address Bool -> Bool -> Expectation
forall a. (HasCallStack, Show a, Eq a) => a -> a -> Expectation
`shouldBe` Bool
False

matches :: ServerOutput Tx -> Text -> Bool
matches :: ServerOutput Tx -> Text -> Bool
matches ServerOutput Tx
output =
  ServerOutputFilter Tx -> TimedServerOutput Tx -> Text -> Bool
forall tx.
ServerOutputFilter tx -> TimedServerOutput tx -> Text -> Bool
txContainsAddr ServerOutputFilter Tx
serverOutputFilter TimedServerOutput Tx
timed
 where
  timed :: TimedServerOutput Tx
timed = TimedServerOutput{$sel:seq:TimedServerOutput :: Natural
seq = Natural
0, $sel:time:TimedServerOutput :: UTCTime
time = POSIXTime -> UTCTime
posixSecondsToUTCTime POSIXTime
0, ServerOutput Tx
output :: ServerOutput Tx
$sel:output:TimedServerOutput :: ServerOutput Tx
output}

bech32Of :: AddressInEra -> Text
bech32Of :: AddressInEra -> Text
bech32Of = \case
  ShelleyAddressInEra Address ShelleyAddr
addr -> Address ShelleyAddr -> Text
forall a. SerialiseAsBech32 a => a -> Text
serialiseToBech32 Address ShelleyAddr
addr
  ByronAddressInEra{} -> Text -> Text
forall a t. (HasCallStack, IsText t) => t -> a
error Text
"unexpected Byron address in fixture"