Skip to content

Commit

Permalink
Fix protocol version error messages happening during synchronisation. (
Browse files Browse the repository at this point in the history
…#243)

* Refactorings:

* Moved ChainSyncHandle from Cardano.Node.Client to Cardano.Node.Types

* Add a function that starts the configured node.

* Make the alonzo node command not exit.

* Make the tx sender optional.

The tx sender is only used when mocking the node in order to provide a
way to send transactions unto the network. It was never actually used
when connecting to the real node, however the sender thread was started
and caused connection errors since it was trying to connect to a
differently versioned real node.

* Make ChainIndex update ccaAvailability

* Throw errors and log them if trying to send txs.
  • Loading branch information
Radu Ometita authored Jan 21, 2022
1 parent 4725d9e commit 5ffdb63
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 55 deletions.
16 changes: 8 additions & 8 deletions plutus-pab-executables/plutus-pab.yaml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ walletServerConfig:
baseUrl: http://localhost:9081

nodeServerConfig:
mscBaseUrl: http://localhost:9082
mscSocketPath: ./node-server.sock
mscKeptBlocks: 100
mscNetworkId: "1097911063" # Testnet network ID (main net = empty string)
mscSlotConfig:
pscBaseUrl: http://localhost:9082
pscSocketPath: ./node-server.sock
pscKeptBlocks: 100
pscNetworkId: "1097911063" # Testnet network ID (main net = empty string)
pscSlotConfig:
scSlotZeroTime: 1596059091000 # Wednesday, July 29, 2020 21:44:51 - shelley launch time in milliseconds
scSlotLength: 1000 # In milliseconds
mscFeeConfig:
pscFeeConfig:
fcConstantFee:
getLovelace: 10 # Constant fee per transaction in lovelace
fcScriptsFeeFactor: 1.0 # Factor by which to multiply size-dependent scripts fee in lovelace
mscInitialTxWallets:
pscInitialTxWallets:
- getWallet: 1
- getWallet: 2
- getWallet: 3
mscNodeMode: MockNode
pscNodeMode: MockNode

chainIndexConfig:
ciBaseUrl: http://localhost:9083
Expand Down
17 changes: 9 additions & 8 deletions plutus-pab-executables/tx-inject/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@ walletServerConfig:
baseUrl: http://localhost:9081

nodeServerConfig:
mscBaseUrl: http://localhost:9082
mscSocketPath: /tmp/node-server.sock
mscKeptBlocks: 100000
mscNetworkId: "1097911063"
mscSlotConfig:
pscBaseUrl: http://localhost:9082
pscSocketPath: /tmp/node-server.sock
pscKeptBlocks: 100000
# pscNetworkId: "1097911063"
pscNetworkId: "3"
pscSlotConfig:
scSlotZeroTime: 1596059091000 # Wednesday, July 29, 2020 21:44:51 - shelley launch time in milliseconds
scSlotLength: 1000 # In milliseconds
mscFeeConfig:
pscFeeConfig:
fcConstantFee:
getLovelace: 10 # Constant fee per transaction in lovelace
fcScriptsFeeFactor: 1.0 # Factor by which to multiply size-dependent scripts fee in lovelace
mscInitialTxWallets:
pscInitialTxWallets:
- getWallet: 1
- getWallet: 2
- getWallet: 3
Expand All @@ -35,7 +36,7 @@ nodeServerConfig:
- getWallet: 8
- getWallet: 9
- getWallet: 10
mscNodeMode: AlonzoNode
pscNodeMode: AlonzoNode

chainIndexConfig:
ciBaseUrl: http://localhost:9083
Expand Down
6 changes: 4 additions & 2 deletions plutus-pab/src/Cardano/ChainIndex/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module Cardano.ChainIndex.Server(
, ChainIndexServerMsg
) where

import Control.Concurrent.Availability (Availability, available)
import Control.Concurrent.STM (TVar)
import Control.Concurrent.STM qualified as STM
import Control.Monad.Freer.Extras.Log
Expand All @@ -34,14 +35,15 @@ import Plutus.ChainIndex.Emulator (ChainIndexEmulatorState, serveChainIndexQuery
-- The PAB chain index that keeps track of transaction data (UTXO set enriched
-- with datums)

main :: ChainIndexTrace -> ChainIndexConfig -> FilePath -> SlotConfig -> IO ()
main trace ChainIndexConfig{ciBaseUrl} socketPath slotConfig = runLogEffects trace $ do
main :: ChainIndexTrace -> ChainIndexConfig -> FilePath -> SlotConfig -> Availability -> IO ()
main trace ChainIndexConfig{ciBaseUrl} socketPath slotConfig ccaAvailability = runLogEffects trace $ do
tVarState <- liftIO $ STM.atomically $ STM.newTVar mempty

logInfo StartingNodeClientThread
_ <- liftIO $ runChainSync socketPath slotConfig $ updateChainState tVarState

logInfo $ StartingChainIndex servicePort
available ccaAvailability
liftIO $ serveChainIndexQueryServer servicePort tVarState
where
servicePort = baseUrlPort (coerce ciBaseUrl)
Expand Down
41 changes: 35 additions & 6 deletions plutus-pab/src/Cardano/Node/Client.hs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Cardano.Node.Client where

import Control.Monad.Freer
import Control.Monad.Freer.Error (Error, throwError)
import Control.Monad.Freer.Reader (Reader, ask)
import Control.Monad.IO.Class
import Data.Proxy (Proxy (Proxy))
import Ledger (Block)
import Ledger.TimeSlot (SlotConfig)
import Servant (NoContent, (:<|>) (..))
import Servant.Client (ClientM, client)

import Cardano.Api.NetworkId.Extra (NetworkIdWrapper (..))
import Cardano.Node.API (API)
import Cardano.Node.Types (PABServerLogMsg)
import Cardano.Node.Types (ChainSyncHandle, NodeMode (..), PABServerConfig (..), PABServerLogMsg)
import Cardano.Protocol.Socket.Client qualified as Client
import Cardano.Protocol.Socket.Mock.Client qualified as MockClient
import Control.Monad.Freer.Extras.Log (LogMessage)
import Plutus.PAB.Types (PABError (..))
import Wallet.Effects (NodeClientEffect (..))

healthcheck :: ClientM NoContent
Expand All @@ -37,19 +40,45 @@ handleNodeClientClient ::
forall m effs.
( LastMember m effs
, MonadIO m
, Member (Reader MockClient.TxSendHandle) effs
, Member (Error PABError) effs
, Member (Reader (Maybe MockClient.TxSendHandle)) effs
, Member (Reader ChainSyncHandle) effs
)
=> SlotConfig
-> NodeClientEffect
~> Eff effs
handleNodeClientClient slotCfg e = do
txSendHandle <- ask @MockClient.TxSendHandle
txSendHandle <- ask @(Maybe MockClient.TxSendHandle)
chainSyncHandle <- ask @ChainSyncHandle
case e of
PublishTx tx -> liftIO $ MockClient.queueTx txSendHandle tx
PublishTx tx ->
case txSendHandle of
Nothing ->
-- If the PAB is started with the real node working transactions
-- need to be sent via the wallet, not the mocked server node
-- (which is not actually running).
throwError TxSenderNotAvailable
Just handle -> liftIO $ MockClient.queueTx handle tx
GetClientSlot ->
either (liftIO . MockClient.getCurrentSlot) (liftIO . Client.getCurrentSlot) chainSyncHandle
GetClientSlotConfig -> pure slotCfg

type ChainSyncHandle = Either (Client.ChainSyncHandle Block) (Client.ChainSyncHandle Client.ChainSyncEvent)
-- | This does not seem to support resuming so it means that the slot tick will
-- be behind everything else. This is due to having 2 connections to the node
-- one for chainSync/block transfer and one for chainSync/currentSlot information.
-- TODO: Think about merging the two functionalities, or keep them in sync.
runChainSyncWithCfg ::
PABServerConfig
-> IO ChainSyncHandle
runChainSyncWithCfg PABServerConfig { pscSocketPath
, pscNodeMode
, pscNetworkId
, pscSlotConfig } =
case pscNodeMode of
AlonzoNode ->
Right <$> Client.runChainSync' pscSocketPath
pscSlotConfig
(unNetworkIdWrapper pscNetworkId)
[]
MockNode ->
Left <$> MockClient.runChainSync' pscSocketPath pscSlotConfig
11 changes: 7 additions & 4 deletions plutus-pab/src/Cardano/Node/Mock.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,25 @@ consumeEventHistory stateVar =

addTx ::
( Member (LogMsg PABServerLogMsg) effs
, Member (Reader Client.TxSendHandle) effs
, Member (Reader (Maybe Client.TxSendHandle)) effs
, MonadIO m
, LastMember m effs
)
=> Tx -> Eff effs NoContent
addTx tx = do
logInfo $ BlockOperation $ NewTransaction tx
clientHandler <- Eff.ask
liftIO $ Client.queueTx clientHandler tx
case clientHandler of
Nothing -> logError TxSendCalledWithoutMock
Just handler ->
liftIO $ Client.queueTx handler tx
pure NoContent

-- | Run all chain effects in the IO Monad
runChainEffects ::
Trace IO PABServerLogMsg
-> SlotConfig
-> Client.TxSendHandle
-> Maybe Client.TxSendHandle
-> MVar AppState
-> Eff (NodeServerEffects IO) a
-> IO ([LogMessage PABServerLogMsg], a)
Expand Down Expand Up @@ -99,7 +102,7 @@ runChainEffects trace slotCfg clientHandler stateVar eff = do
processChainEffects ::
Trace IO PABServerLogMsg
-> SlotConfig
-> Client.TxSendHandle
-> Maybe Client.TxSendHandle
-> MVar AppState
-> Eff (NodeServerEffects IO) a
-> IO a
Expand Down
2 changes: 1 addition & 1 deletion plutus-pab/src/Cardano/Node/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ app trace slotCfg clientHandler stateVar =
serve (Proxy @API) $
hoistServer
(Proxy @API)
(liftIO . processChainEffects trace slotCfg clientHandler stateVar)
(liftIO . processChainEffects trace slotCfg (Just clientHandler) stateVar)
(healthcheck :<|> consumeEventHistory stateVar)

data Ctx = Ctx { serverHandler :: Server.ServerHandler
Expand Down
13 changes: 11 additions & 2 deletions plutus-pab/src/Cardano/Node/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module Cardano.Node.Types

-- * Effects
, NodeServerEffects
, ChainSyncHandle

-- * State types
, AppState (..)
Expand All @@ -45,6 +46,7 @@ module Cardano.Node.Types
import Cardano.BM.Data.Tracer (ToObject (..))
import Cardano.BM.Data.Tracer.Extras (Tagged (..), mkObjectStr)
import Cardano.Chain (MockNodeServerChainState, fromEmulatorChainState)
import Cardano.Protocol.Socket.Client qualified as Client
import Cardano.Protocol.Socket.Mock.Client qualified as Client
import Control.Lens (makeLenses, view)
import Control.Monad.Freer.Extras.Log (LogMessage, LogMsg (..))
Expand All @@ -60,7 +62,7 @@ import Data.Time.Format.ISO8601 qualified as F
import Data.Time.Units (Millisecond)
import Data.Time.Units.Extra ()
import GHC.Generics (Generic)
import Ledger (Tx, txId)
import Ledger (Block, Tx, txId)
import Ledger.CardanoWallet (WalletNumber (..))
import Ledger.TimeSlot (SlotConfig)
import Plutus.Contract.Trace qualified as Trace
Expand Down Expand Up @@ -157,6 +159,10 @@ defaultPABServerConfig =
instance Default PABServerConfig where
def = defaultPABServerConfig

-- | The types of handles varies based on the type of clients (mocked or
-- real nodes) and we need a generic way of handling either type of response.
type ChainSyncHandle = Either (Client.ChainSyncHandle Block) (Client.ChainSyncHandle Client.ChainSyncEvent)

-- Logging ------------------------------------------------------------------------------------------------------------

-- | Top-level logging data type for structural logging
Expand All @@ -171,6 +177,7 @@ data PABServerLogMsg =
| ProcessingChainEvent ChainEvent
| BlockOperation BlockEvent
| CreatingRandomTransaction
| TxSendCalledWithoutMock
deriving (Generic, Show, ToJSON, FromJSON)

instance Pretty PABServerLogMsg where
Expand All @@ -187,6 +194,7 @@ instance Pretty PABServerLogMsg where
ProcessingChainEvent e -> "Processing chain event" <+> pretty e
BlockOperation e -> "Block operation" <+> pretty e
CreatingRandomTransaction -> "Generating a random transaction"
TxSendCalledWithoutMock -> "Cannot send transaction without a mocked environment."

instance ToObject PABServerLogMsg where
toObject _ = \case
Expand All @@ -199,6 +207,7 @@ instance ToObject PABServerLogMsg where
ProcessingChainEvent e -> mkObjectStr "Processing chain event" (Tagged @"event" e)
BlockOperation e -> mkObjectStr "Block operation" (Tagged @"event" e)
CreatingRandomTransaction -> mkObjectStr "Creating random transaction" ()
TxSendCalledWithoutMock -> mkObjectStr "Cannot send transaction without a mocked environment." ()

data BlockEvent = NewSlot
| NewTransaction Tx
Expand Down Expand Up @@ -245,7 +254,7 @@ type NodeServerEffects m
, ChainEffect
, State MockNodeServerChainState
, LogMsg PABServerLogMsg
, Reader Client.TxSendHandle
, Reader (Maybe Client.TxSendHandle)
, State AppState
, LogMsg PABServerLogMsg
, m]
18 changes: 13 additions & 5 deletions plutus-pab/src/Cardano/Wallet/Mock/Handlers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Cardano.Wallet.Mock.Handlers

import Cardano.BM.Data.Trace (Trace)
import Cardano.Node.Client qualified as NodeClient
import Cardano.Node.Types (ChainSyncHandle)
import Cardano.Protocol.Socket.Mock.Client qualified as MockClient
import Cardano.Wallet.Mock.Types (MultiWalletEffect (..), WalletEffects, WalletInfo (..), WalletMsg (..), Wallets,
fromWalletState)
Expand All @@ -29,7 +30,7 @@ import Control.Monad.Error (MonadError)
import Control.Monad.Except qualified as MonadError
import Control.Monad.Freer
import Control.Monad.Freer.Error
import Control.Monad.Freer.Extras
import Control.Monad.Freer.Extras hiding (Error)
import Control.Monad.Freer.Reader (runReader)
import Control.Monad.Freer.State (State, evalState, get, put, runState)
import Control.Monad.IO.Class (MonadIO, liftIO)
Expand All @@ -42,7 +43,7 @@ import Data.ByteString.Lazy.Char8 qualified as BSL8
import Data.ByteString.Lazy.Char8 qualified as Char8
import Data.Function ((&))
import Data.Map qualified as Map
import Data.Text (Text)
import Data.Text (Text, pack)
import Data.Text.Encoding (encodeUtf8)
import Ledger.Ada qualified as Ada
import Ledger.Address (PaymentPubKeyHash)
Expand All @@ -55,6 +56,7 @@ import Plutus.ChainIndex (ChainIndexQueryEffect)
import Plutus.ChainIndex.Client qualified as ChainIndex
import Plutus.PAB.Arbitrary ()
import Plutus.PAB.Monitoring.Monitoring qualified as LM
import Plutus.PAB.Types (PABError)
import Prettyprinter (pretty)
import Servant (ServerError (..), err400, err401, err404)
import Servant.Client (ClientEnv)
Expand Down Expand Up @@ -149,7 +151,7 @@ processWalletEffects ::
(MonadIO m, MonadError ServerError m)
=> Trace IO WalletMsg -- ^ trace for logging
-> MockClient.TxSendHandle -- ^ node client
-> NodeClient.ChainSyncHandle -- ^ node client
-> ChainSyncHandle -- ^ node client
-> ClientEnv -- ^ chain index client
-> MVar Wallets -- ^ wallets state
-> FeeConfig
Expand Down Expand Up @@ -178,7 +180,7 @@ processWalletEffects trace txSendHandle chainSyncHandle chainIndexEnv mVarState
runWalletEffects ::
Trace IO WalletMsg -- ^ trace for logging
-> MockClient.TxSendHandle -- ^ node client
-> NodeClient.ChainSyncHandle -- ^ node client
-> ChainSyncHandle -- ^ node client
-> ClientEnv -- ^ chain index client
-> Wallets -- ^ current state
-> FeeConfig
Expand All @@ -190,10 +192,12 @@ runWalletEffects trace txSendHandle chainSyncHandle chainIndexEnv wallets feeCfg
& interpret (LM.handleLogMsgTrace trace)
& reinterpret2 (NodeClient.handleNodeClientClient slotCfg)
& runReader chainSyncHandle
& runReader txSendHandle
& runReader (Just txSendHandle)
& reinterpret ChainIndex.handleChainIndexClient
& runReader chainIndexEnv
& runState wallets
& flip catchError logPabErrorAndRethrow
& handlePrettyErrors
& interpret (LM.handleLogMsgTrace (toWalletMsg trace))
& handleWalletApiErrors
& handleClientErrors
Expand All @@ -202,7 +206,11 @@ runWalletEffects trace txSendHandle chainSyncHandle chainIndexEnv wallets feeCfg
where
handleWalletApiErrors = flip handleError (throwError . fromWalletAPIError)
handleClientErrors = flip handleError (\e -> throwError $ err500 { errBody = Char8.pack (show e) })
handlePrettyErrors = flip handleError (\e -> throwError $ err500 { errBody = Char8.pack (show $ pretty e) })
toWalletMsg = LM.convertLog ChainClientMsg
logPabErrorAndRethrow (e :: PABError) = do
logError (pack $ show $ pretty e)
throwError e

-- | Convert Wallet errors to Servant error responses
fromWalletAPIError :: WalletAPIError -> ServerError
Expand Down
4 changes: 2 additions & 2 deletions plutus-pab/src/Cardano/Wallet/Mock/Server.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module Cardano.Wallet.Mock.Server

import Cardano.BM.Data.Trace (Trace)
import Cardano.ChainIndex.Types (ChainIndexUrl (ChainIndexUrl))
import Cardano.Node.Client qualified as NodeClient
import Cardano.Node.Types (ChainSyncHandle)
import Cardano.Protocol.Socket.Mock.Client qualified as MockClient
import Cardano.Wallet.Mock.API (API)
import Cardano.Wallet.Mock.Handlers (processWalletEffects)
Expand Down Expand Up @@ -47,7 +47,7 @@ import Wallet.Emulator.Wallet qualified as Wallet

app :: Trace IO WalletMsg
-> MockClient.TxSendHandle
-> NodeClient.ChainSyncHandle
-> ChainSyncHandle
-> ClientEnv
-> MVar Wallets
-> FeeConfig
Expand Down
Loading

0 comments on commit 5ffdb63

Please sign in to comment.