btc-lsp-0.1.0.0: test/LnChanWatcherSpec.hs
{-# LANGUAGE TypeApplications #-}
module LnChanWatcherSpec
( spec,
)
where
import BtcLsp.Import hiding (newEmptyMVar, putMVar, takeMVar)
import qualified BtcLsp.Storage.Model.LnChan as LnChan
import LndClient
import qualified LndClient.Data.ChannelPoint as Lnd
import qualified LndClient.Data.CloseChannel as Lnd
import LndClient.Data.GetInfo
import qualified LndClient.Data.OpenChannel as OpenChannel
import LndClient.LndTest
import qualified LndClient.RPC.Silent as Lnd
import Test.Hspec
import TestAppM
import UnliftIO.Concurrent (killThread, threadDelay)
openChannelRequest ::
NodePubKey ->
OpenChannel.OpenChannelRequest
openChannelRequest nodePubkey =
OpenChannel.OpenChannelRequest
{ OpenChannel.nodePubkey = nodePubkey,
OpenChannel.localFundingAmount = MSat 200000000,
OpenChannel.pushMSat = Just $ MSat 10000000,
OpenChannel.targetConf = Nothing,
OpenChannel.mSatPerByte = Nothing,
OpenChannel.private = Nothing,
OpenChannel.minHtlcMsat = Nothing,
OpenChannel.remoteCsvDelay = Nothing,
OpenChannel.minConfs = Nothing,
OpenChannel.spendUnconfirmed = Nothing,
OpenChannel.closeAddress = Nothing,
OpenChannel.fundingShim = Nothing
}
closeChannelRequest ::
Lnd.ChannelPoint ->
Lnd.CloseChannelRequest
closeChannelRequest cp =
Lnd.CloseChannelRequest cp False Nothing Nothing Nothing
getNodePubKey :: MonadUnliftIO m => LndEnv -> m NodePubKey
getNodePubKey lndEnv = do
GetInfoResponse merchantPubKey _ _ <-
liftLndResult =<< Lnd.getInfo lndEnv
pure merchantPubKey
queryChannel ::
( Storage m
) =>
Lnd.ChannelPoint ->
m (Maybe (Entity LnChan))
queryChannel (Lnd.ChannelPoint txid vout) =
runSql $
LnChan.getByChannelPointSql txid vout
tryTimes ::
MonadUnliftIO m =>
Int ->
Int ->
m (Maybe a) ->
m (Maybe a)
tryTimes times delaySec tryFn = go times
where
go 0 = pure Nothing
go n = do
res <- tryFn
case res of
Just r -> pure $ Just r
Nothing -> threadDelay (delaySec * 1000000) >> go (n - 1)
justTrue :: Maybe Bool -> Maybe Bool
justTrue (Just True) = Just True
justTrue _ = Nothing
testFun ::
( LndTest m TestOwner,
Storage m
) =>
m [Maybe Bool]
testFun = do
lndFrom <- getLndEnv LndLsp
lndTo <- getLndEnv LndAlice
toPubKey <- getNodePubKey lndTo
cp <-
liftLndResult
=<< Lnd.openChannelSync
lndFrom
(openChannelRequest toPubKey)
isPendingOpenOk <-
tryTimes 3 1 $
justTrue
. fmap
( (== LnChanStatusPendingOpen)
. lnChanStatus
. entityVal
)
<$> queryChannel cp
mine 10 LndLsp
isOpenedOk <- tryTimes 3 1 $ do
ch <- fmap entityVal <$> queryChannel cp
let r =
and
<$> sequence
[(== LnChanStatusActive) . lnChanStatus <$> ch]
pure $ justTrue r
isBackedUp <- tryTimes 3 1 $ do
ch <- fmap entityVal <$> queryChannel cp
let r =
and
<$> sequence
[isJust . lnChanBak <$> ch]
pure $ justTrue r
(ctid, _) <- forkThread $ do
void $
liftLndResult
=<< Lnd.closeChannel
(const $ pure ())
lndFrom
(closeChannelRequest cp)
isInactivedOk <- tryTimes 3 1 $ do
ch <- fmap entityVal <$> queryChannel cp
let r =
and
<$> sequence
[(== LnChanStatusInactive) . lnChanStatus <$> ch]
pure $ justTrue r
mine 10 LndLsp
isClosedOk <- tryTimes 3 1 $ do
ch <- fmap entityVal <$> queryChannel cp
let r =
and
<$> sequence
[ ( `elem`
[ LnChanStatusFullyResolved,
LnChanStatusClosed
]
)
. lnChanStatus
<$> ch
]
pure $ justTrue r
void $ killThread ctid
pure
[ isPendingOpenOk,
isOpenedOk,
isBackedUp,
isInactivedOk,
isClosedOk
]
spec :: Spec
spec =
itMain @'LndLsp "Watch channel" $ do
r <- testFun
liftIO $ r `shouldSatisfy` all (== Just True)