solana-haskell-sdk-1.2.0.0: test-integration/Test/Integration/WebSocket.hs
-- | Live PubSub coverage: confirm a real transaction by subscribing to its
-- signature over a WebSocket instead of polling for its status.
--
-- This is also the worked example of wiring
-- 'Network.Solana.RPC.WebSocket.WsTransport' to the @websockets@ package,
-- which the SDK deliberately does not depend on (see that module's header).
module Test.Integration.WebSocket (tests) where
import Control.Exception (throwIO)
import Control.Monad.IO.Class (liftIO)
import Network.Solana.Core.Crypto (SolanaPublicKey, SolanaSignature, createSolanaKeyPair)
import Network.Solana.Core.Message (newTransactionIntentWithPayer)
import Network.Solana.NativePrograms.SystemProgram qualified as SystemProgram
import Network.Solana.RPC.HTTP.Account (getBalance)
import Network.Solana.RPC.HTTP.Block (getTheLatestBlockhash)
import Network.Solana.RPC.WebSocket
import Network.Web3.Provider (Web3)
import Network.WebSockets qualified as WS
import Test.Integration.Setup
import Test.Tasty
import Test.Tasty.HUnit
tests :: TestTree
tests =
testGroup
"WebSocket"
[testCase "signature subscription pushes the confirmation" wsConfirmFlow]
-- | Submits a transfer, then waits for its confirmation over the PubSub
-- endpoint rather than polling.
--
-- The transaction is sent first and subscribed to immediately afterwards, at
-- @finalized@ commitment: finalization takes on the order of ten seconds even
-- on a local validator, so the subscription is established far in advance of
-- the notification it is waiting for.
wsConfirmFlow :: IO ()
wsConfirmFlow = do
(recipient, sig) <- run submitTransfer
(host, port) <- wsEndpoint
result <-
WS.runClient host port "/" $ \conn ->
let transport = WsTransport (WS.sendTextData conn) (WS.receiveData conn)
in awaitSignature transport (RequestId 1) (Just "finalized") 90 sig
slot <- either assertFailure' pure result
assertBool "confirmation reports a real slot" (slot > 0)
balance <- run (getBalance recipient)
balance @?= 400_000_000
-- | Airdrops a payer and sends it a transfer, returning the recipient and the
-- submitted signature without waiting for confirmation -- that is what the
-- subscription is for.
submitTransfer :: Web3 (SolanaPublicKey, SolanaSignature)
submitTransfer = do
(payerPk, payerSk) <- fundedKeypair 2_000_000_000
recipient <- fst <$> liftIO createSolanaKeyPair
bh <- getTheLatestBlockhash
tx <-
either
(liftIO . throwIO)
pure
(newTransactionIntentWithPayer payerPk [payerSk] [SystemProgram.transfer payerPk recipient 400_000_000] bh)
sig <- sendConfirmedPreflight tx
pure (recipient, sig)
assertFailure' :: String -> IO a
assertFailure' = assertFailure