btc-lsp-0.1.0.0: src/BtcLsp/Grpc/Client/HighLevel.hs
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module BtcLsp.Grpc.Client.HighLevel
( swapIntoLn,
swapIntoLnT,
getCfg,
getCfgT,
)
where
import BtcLsp.Grpc.Client.LowLevel
import BtcLsp.Import
import qualified Data.Binary.Builder as BS
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import Data.ProtoLens.Field
import Data.ProtoLens.Message
import qualified LndClient.Data.VerifyMessage as Lnd
import qualified LndClient.RPC.Katip as Lnd
import qualified Network.GRPC.HTTP2.Encoding as G
import Network.GRPC.HTTP2.ProtoLens (RPC (..))
import Proto.BtcLsp (Service)
import qualified Proto.BtcLsp.Data.HighLevel as Proto
import qualified Proto.BtcLsp.Data.HighLevel_Fields as Proto
import qualified Proto.BtcLsp.Method.GetCfg as GetCfg
import qualified Proto.BtcLsp.Method.SwapIntoLn as SwapIntoLn
swapIntoLn ::
( Env m
) =>
GCEnv ->
SwapIntoLn.Request ->
m (Either Failure SwapIntoLn.Response)
swapIntoLn env req = withRunInIO $ \run ->
first (FailureInt . FailureGrpcClient)
<$> runUnary
(RPC :: RPC Service "swapIntoLn")
env
( \res sig compressMode ->
run $
verifySig res sig compressMode
)
req
swapIntoLnT ::
( Env m
) =>
GCEnv ->
SwapIntoLn.Request ->
ExceptT Failure m SwapIntoLn.Response
swapIntoLnT env =
ExceptT . swapIntoLn env
getCfg ::
( Env m
) =>
GCEnv ->
GetCfg.Request ->
m (Either Failure GetCfg.Response)
getCfg env req = withRunInIO $ \run ->
first (FailureInt . FailureGrpcClient)
<$> runUnary
(RPC :: RPC Service "getCfg")
env
( \res sig compressMode ->
run $
verifySig res sig compressMode
)
req
getCfgT ::
( Env m
) =>
GCEnv ->
GetCfg.Request ->
ExceptT Failure m GetCfg.Response
getCfgT env =
ExceptT . getCfg env
-- | WARNING : this function is unsafe and inefficient
-- but it is used for testing purposes only!
verifySig ::
( Env m,
Message msg,
HasField msg "ctx" Proto.Ctx
) =>
msg ->
ByteString ->
CompressMode ->
m Bool
verifySig msg sig compressMode = do
let msgEncoded =
encodeMessage msg
let msgChunk =
case compressMode of
Compressed -> G._compressionFunction G.gzip msgEncoded
Uncompressed -> msgEncoded
let msgWire =
BS.pack
[ case compressMode of
Compressed -> 1
Uncompressed -> 0
]
<> ( BL.toStrict
. BS.toLazyByteString
. BS.putWord32be
. fromIntegral -- Length is non-neg, it's fine.
$ BS.length msgChunk
)
<> msgChunk
let pub =
msg
^. field @"ctx"
. Proto.lnPubKey
. Proto.val
res <-
withLnd
Lnd.verifyMessage
( $
Lnd.VerifyMessageRequest
{ Lnd.message = msgWire,
Lnd.signature = sig,
Lnd.pubkey = pub
}
)
case res of
Left e -> do
$(logTM) ErrorS . logStr $
"Client ==> signature verification failed "
<> inspect e
pure False
Right x ->
if coerce x
then pure True
else do
$(logTM) ErrorS . logStr $
"Client ==> signature verification failed "
<> "for message of "
<> inspect (BS.length msgWire)
<> " bytes "
<> inspect msgWire
<> " with signature of "
<> inspect (BS.length sig)
<> " bytes "
<> inspect sig
<> " and pub key "
<> inspect pub
pure False