diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index b5e72b69b20..7aeeeb6343b 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -143,9 +143,16 @@ steps: concurrency: 1 concurrency_group: 'linux-e2e-tests' - - label: Private Network Full Sync + - label: Build .#cardano-wallet (linux) + key: cardano-wallet depends_on: linux-nix - timeout: 20 + command: 'nix build .#cardano-wallet' + agents: + system: ${linux} + + - label: Private Network Full Sync + depends_on: cardano-wallet + timeout: 10 command: | rm -rf run/private/nix/logs mkdir -p run/private/nix/logs @@ -158,10 +165,12 @@ steps: env: NODE_LOGS_FILE: ./logs/node.log WALLET_LOGS_FILE: ./logs/wallet.log + CLEANUP_DB: true + NETWORK: testnet - label: Mainnet Boot Sync - depends_on: linux-nix - timeout: 30 + depends_on: cardano-wallet + timeout: 2 command: | cd run/mainnet/nix rm -rf logs @@ -176,17 +185,19 @@ steps: SUCCESS_STATUS: syncing NODE_LOGS_FILE: ./logs/node.log WALLET_LOGS_FILE: ./logs/wallet.log + CLEANUP_DB: true + NETWORK: mainnet - block: Sanchonet Full Sync if: build.env("RELEASE_CANDIDATE") == null - depends_on: linux-nix + depends_on: cardano-wallet key: linux-sanchonet-full-sync-block - label: Sanchonet Full Sync depends_on: - - linux-nix + - cardano-wallet - linux-sanchonet-full-sync-block - timeout_in_minutes: 240 + timeout_in_minutes: 30 command: | rm -rf run/sanchonet/nix/logs mkdir -p run/sanchonet/nix/logs @@ -199,6 +210,8 @@ steps: env: NODE_LOGS_FILE: ./logs/node.log WALLET_LOGS_FILE: ./logs/wallet.log + CLEANUP_DB: true + NETWORK: testnet - block: Preprod Full Sync if: build.env("RELEASE_CANDIDATE") == null @@ -207,9 +220,9 @@ steps: - label: Preprod Full Sync depends_on: - - linux-nix + - cardano-wallet - linux-preprod-full-sync-block - timeout_in_minutes: 240 + timeout_in_minutes: 30 command: | cd run/preprod/nix rm -rf logs @@ -224,6 +237,8 @@ steps: env: NODE_LOGS_FILE: ./logs/node.log WALLET_LOGS_FILE: ./logs/wallet.log + CLEANUP_DB: true + NETWORK: testnet - group: Code Quality Checks diff --git a/lib/api/cardano-wallet-api.cabal b/lib/api/cardano-wallet-api.cabal index c0f711e768d..1b99f38a124 100644 --- a/lib/api/cardano-wallet-api.cabal +++ b/lib/api/cardano-wallet-api.cabal @@ -58,7 +58,6 @@ library , containers , contra-tracer , crypto-primitives - , data-default , deepseq , either , errors @@ -73,7 +72,6 @@ library , iohk-monitoring , memory , mtl - , network , network-uri , OddWord , quiet @@ -82,20 +80,12 @@ library , servant , servant-client , servant-server - , streaming-commons , text , text-class , time - , tls , transformers , unliftio , wai - , wai-middleware-logging - , warp - , warp-tls - , x509 - , x509-store - , x509-validation exposed-modules: Cardano.Wallet.Api @@ -116,7 +106,6 @@ library Cardano.Wallet.Api.Http.Server.Error.IsServerError Cardano.Wallet.Api.Http.Server.Handlers.MintBurn Cardano.Wallet.Api.Http.Server.Handlers.TxCBOR - Cardano.Wallet.Api.Http.Server.Tls Cardano.Wallet.Api.Http.Shelley.Server Cardano.Wallet.Api.Lib.ApiAsArray Cardano.Wallet.Api.Lib.ApiT diff --git a/lib/api/src/Cardano/Wallet/Api/Http/Logging.hs b/lib/api/src/Cardano/Wallet/Api/Http/Logging.hs index 4290ebd8b7e..d2839543762 100644 --- a/lib/api/src/Cardano/Wallet/Api/Http/Logging.hs +++ b/lib/api/src/Cardano/Wallet/Api/Http/Logging.hs @@ -10,7 +10,7 @@ -- Logging functionality for the Shelley wallet -- module Cardano.Wallet.Api.Http.Logging - ( ApplicationLog(..) + ( ApiApplicationLog(..) ) where import Prelude @@ -26,9 +26,6 @@ import Cardano.BM.Tracing import Cardano.Launcher.Node ( CardanoNodeConn ) -import Cardano.Wallet.Api.Http.Shelley.Server - ( ListenError (..) - ) import Data.Text ( Text ) @@ -46,35 +43,18 @@ import Network.URI import qualified Data.Text as T -- | Log messages related to application startup and shutdown. -data ApplicationLog +data ApiApplicationLog = MsgStartingNode CardanoNodeConn | MsgNetworkName Text - | MsgServerStartupError ListenError | MsgFailedConnectSMASH URI deriving (Generic, Show, Eq) -instance ToText ApplicationLog where +instance ToText ApiApplicationLog where toText = \case MsgStartingNode conn -> "Wallet backend server starting. Using " <> toText conn <> "." MsgNetworkName network -> "Node is Haskell Node on " <> network <> "." - MsgServerStartupError startupErr -> case startupErr of - ListenErrorHostDoesNotExist host -> mempty - <> "Can't listen on " - <> T.pack (show host) - <> ". It does not exist." - ListenErrorInvalidAddress host -> mempty - <> "Can't listen on " - <> T.pack (show host) - <> ". Invalid address." - ListenErrorAddressAlreadyInUse mPort -> mempty - <> "The API server listen port " - <> maybe "(unknown)" (T.pack . show) mPort - <> " is already in use." - ListenErrorOperationNotPermitted -> mempty - <> "Cannot listen on the given port. " - <> "The operation is not permitted." MsgFailedConnectSMASH uri -> T.unwords [ "Failed connect to the given smash server\ \ or validate a healthy status." @@ -82,10 +62,9 @@ instance ToText ApplicationLog where , T.pack $ uriToString id uri "" ] -instance HasPrivacyAnnotation ApplicationLog -instance HasSeverityAnnotation ApplicationLog where +instance HasPrivacyAnnotation ApiApplicationLog +instance HasSeverityAnnotation ApiApplicationLog where getSeverityAnnotation = \case MsgStartingNode _ -> Info MsgNetworkName _ -> Info - MsgServerStartupError _ -> Alert MsgFailedConnectSMASH _ -> Warning diff --git a/lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs b/lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs index 85be8e5b5cf..e756687539f 100644 --- a/lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs +++ b/lib/api/src/Cardano/Wallet/Api/Http/Shelley/Server.hs @@ -37,16 +37,9 @@ module Cardano.Wallet.Api.Http.Shelley.Server ( - -- * Server Configuration - Listen (..) - , ListenError (..) - , HostPreference - , TlsConfiguration (..) -- * Server Setup - , start - , serve - , withListeningSocket + serve -- * ApiLayer , newApiLayer @@ -136,7 +129,6 @@ module Cardano.Wallet.Api.Http.Shelley.Server -- * Logging , WalletEngineLog (..) - , walletListenFromEnv ) where @@ -336,10 +328,6 @@ import Cardano.Wallet.Api.Http.Server.Handlers.TxCBOR ( ParsedTxCBOR (..) , parseTxCBOR ) -import Cardano.Wallet.Api.Http.Server.Tls - ( TlsConfiguration (..) - , requireClientAuth - ) import Cardano.Wallet.Api.Types ( AccountPostData (..) , AddressAmount (..) @@ -790,8 +778,7 @@ import Data.IntCast ( intCastMaybe ) import Data.List - ( isInfixOf - , sortOn + ( sortOn , (\\) ) import Data.List.NonEmpty @@ -818,14 +805,6 @@ import Data.Quantity import Data.Set ( Set ) -import Data.Streaming.Network - ( HostPreference - , bindPortTCP - , bindRandomPortTCP - ) -import Data.Text - ( Text - ) import Data.Text.Class ( FromText (..) , ToText (..) @@ -863,22 +842,6 @@ import Network.Ntp ( NtpClient , getNtpStatus ) -import Network.Socket - ( Socket - , close - ) -import Network.Wai.Handler.Warp - ( Port - ) -import Network.Wai.Middleware.Logging - ( ApiLog (..) - , newApiLoggerSettings - , obfuscateKeys - , withApiLogger - ) -import Network.Wai.Middleware.ServerError - ( handleRawError - ) import Numeric.Natural ( Natural ) @@ -886,8 +849,7 @@ import Safe ( fromJustNote ) import Servant - ( Application - , NoContent (..) + ( NoContent (..) , err400 , err404 , err500 @@ -897,16 +859,6 @@ import Servant.Server ( Handler (..) , runHandler ) -import System.Exit - ( die - ) -import System.IO.Error - ( ioeGetErrorType - , isAlreadyInUseError - , isDoesNotExistError - , isPermissionError - , isUserError - ) import System.Random ( getStdRandom , random @@ -918,10 +870,7 @@ import UnliftIO.Concurrent ( threadDelay ) import UnliftIO.Exception - ( IOException - , bracket - , tryAnyDeep - , tryJust + ( tryAnyDeep ) import qualified Cardano.Address.Script as CA @@ -1002,119 +951,6 @@ import qualified Internal.Cardano.Write.Tx.Sign as Write , estimateMinWitnessRequiredPerInput ) import qualified Network.Ntp as Ntp -import qualified Network.Wai.Handler.Warp as Warp -import qualified Network.Wai.Handler.WarpTLS as Warp - --- | Allow configuring which port the wallet server listen to in an integration --- setup. Crashes if the variable is not a number. -walletListenFromEnv :: Show e - => (String -> IO (Maybe (Either e Port))) -> IO Listen -walletListenFromEnv envFromText = envFromText "CARDANO_WALLET_PORT" >>= \case - Nothing -> pure ListenOnRandomPort - Just (Right port) -> pure $ ListenOnPort port - Just (Left e) -> die $ show e - --- | How the server should listen for incoming requests. -data Listen - = ListenOnPort Port - -- ^ Listen on given TCP port - | ListenOnRandomPort - -- ^ Listen on an unused TCP port, selected at random - deriving (Show, Eq) - --- | Start the application server, using the given settings and a bound socket. -start - :: Warp.Settings - -> Tracer IO ApiLog - -> Maybe TlsConfiguration - -> Socket - -> Application - -> IO () -start settings tr tlsConfig socket application = do - logSettings <- newApiLoggerSettings <&> obfuscateKeys (const sensitive) - runSocket - $ handleRawError (curry toServerError) - $ withApiLogger tr logSettings - application - where - runSocket :: Application -> IO () - runSocket = case tlsConfig of - Nothing -> Warp.runSettingsSocket settings socket - Just tls -> Warp.runTLSSocket (requireClientAuth tls) settings socket - - sensitive :: [Text] - sensitive = - [ "passphrase" - , "old_passphrase" - , "new_passphrase" - , "mnemonic_sentence" - , "mnemonic_second_factor" - ] - --- | Run an action with a TCP socket bound to a port specified by the `Listen` --- parameter. -withListeningSocket - :: HostPreference - -- ^ Which host to bind. - -> Listen - -- ^ Whether to listen on a given port, or random port. - -> (Either ListenError (Port, Socket) -> IO a) - -- ^ Action to run with listening socket. - -> IO a -withListeningSocket hostPreference portOpt = bracket acquire release - where - acquire = tryJust handleErr bindAndListen - -- Note: These Data.Streaming.Network functions also listen on the socket, - -- even though their name just says "bind". - bindAndListen = case portOpt of - ListenOnPort port -> (port,) <$> bindPortTCP port hostPreference - ListenOnRandomPort -> bindRandomPortTCP hostPreference - release (Right (_, socket)) = liftIO $ close socket - release (Left _) = pure () - handleErr = ioToListenError hostPreference portOpt - -data ListenError - = ListenErrorAddressAlreadyInUse (Maybe Port) - | ListenErrorOperationNotPermitted - | ListenErrorHostDoesNotExist HostPreference - | ListenErrorInvalidAddress HostPreference - deriving (Show, Eq) - -ioToListenError :: HostPreference -> Listen -> IOException -> Maybe ListenError -ioToListenError hostPreference portOpt e - -- A socket is already listening on that address and port - | isAlreadyInUseError e = - Just (ListenErrorAddressAlreadyInUse (listenPort portOpt)) - -- Usually caused by trying to listen on a privileged port - | isPermissionError e = - Just ListenErrorOperationNotPermitted - -- Bad hostname -- Linux and Darwin - | isDoesNotExistError e = - Just (ListenErrorHostDoesNotExist hostPreference) - -- Bad hostname -- Windows - -- WSAHOST_NOT_FOUND, WSATRY_AGAIN, or bind: WSAEOPNOTSUPP - | isUserError e && any hasDescription ["11001", "11002", "10045"] = - Just (ListenErrorHostDoesNotExist hostPreference) - -- Address is valid, but can't be used for listening -- Linux - | show (ioeGetErrorType e) == "invalid argument" = - Just (ListenErrorInvalidAddress hostPreference) - -- Address is valid, but can't be used for listening -- Darwin - | show (ioeGetErrorType e) == "unsupported operation" = - Just (ListenErrorInvalidAddress hostPreference) - -- Address is valid, but can't be used for listening -- Windows - | isOtherError e && any hasDescription ["WSAEINVAL", "WSAEADDRNOTAVAIL"] = - Just (ListenErrorInvalidAddress hostPreference) - -- Listening on an unavailable or privileged port -- Windows - | isOtherError e && hasDescription "WSAEACCESS" = - Just (ListenErrorAddressAlreadyInUse (listenPort portOpt)) - | otherwise = - Nothing - where - listenPort (ListenOnPort port) = Just port - listenPort ListenOnRandomPort = Nothing - - isOtherError ex = show (ioeGetErrorType ex) == "failed" - hasDescription text = text `isInfixOf` show e {------------------------------------------------------------------------------- Wallet Constructors diff --git a/lib/benchmarks/exe/latency-bench.hs b/lib/benchmarks/exe/latency-bench.hs index 3576197b7b7..6f37dd76535 100644 --- a/lib/benchmarks/exe/latency-bench.hs +++ b/lib/benchmarks/exe/latency-bench.hs @@ -37,9 +37,6 @@ import Cardano.BM.Trace import Cardano.Mnemonic ( SomeMnemonic ) -import Cardano.Wallet.Api.Http.Shelley.Server - ( Listen (ListenOnPort) - ) import Cardano.Wallet.Api.Types ( AddressAmount (..) , ApiMnemonicT (..) @@ -71,6 +68,9 @@ import Cardano.Wallet.Application import Cardano.Wallet.Application.CLI ( Port (..) ) +import Cardano.Wallet.Application.Server + ( Listen (ListenOnPort) + ) import Cardano.Wallet.Benchmarks.Collect ( Benchmark (..) , Reporter (..) @@ -742,6 +742,7 @@ withShelleyServer tracers action = withFaucet $ \faucetClientEnv -> do Nothing -- db decorator "127.0.0.1" (ListenOnPort 8_090) + Nothing Nothing -- tls configuration Nothing -- settings Nothing -- token metadata server diff --git a/lib/exe/app/cardano-wallet.hs b/lib/exe/app/cardano-wallet.hs index da5955bdf78..ba5ea0199c2 100644 --- a/lib/exe/app/cardano-wallet.hs +++ b/lib/exe/app/cardano-wallet.hs @@ -20,7 +20,6 @@ -- commands. Commands are turned into corresponding API calls, and submitted -- to an up-and-running server. Some commands do not require an active server -- and can be run "offline". - module Main where import Prelude @@ -58,11 +57,6 @@ import Cardano.Wallet.Api.Client , transactionClient , walletClient ) -import Cardano.Wallet.Api.Http.Shelley.Server - ( HostPreference - , Listen (..) - , TlsConfiguration - ) import Cardano.Wallet.Application ( TracerSeverities , Tracers @@ -91,7 +85,8 @@ import Cardano.Wallet.Application.CLI , enableWindowsANSI , helperTracing , hostPreferenceOption - , listenOption + , listenApiOption + , listenUiOption , loggingMinSeverity , loggingOptions , loggingSeverityOrOffReader @@ -105,6 +100,13 @@ import Cardano.Wallet.Application.CLI , tokenMetadataSourceOption , withLogging ) +import Cardano.Wallet.Application.Server + ( HostPreference + , Listen + ) +import Cardano.Wallet.Application.Tls + ( TlsConfiguration + ) import Cardano.Wallet.Application.Version ( GitRevision , Version @@ -202,16 +204,18 @@ import qualified System.Info as I main :: IO () main = withUtf8 $ do enableWindowsANSI - runCli $ cli $ mempty - <> cmdServe - <> cmdMnemonic - <> cmdKey - <> cmdWallet cmdWalletCreate walletClient - <> cmdAddress addressClient - <> cmdTransaction transactionClient walletClient - <> cmdNetwork networkClient - <> cmdStakePool stakePoolClient - <> cmdVersion + runCli + $ cli + $ mempty + <> cmdServe + <> cmdMnemonic + <> cmdKey + <> cmdWallet cmdWalletCreate walletClient + <> cmdAddress addressClient + <> cmdTransaction transactionClient walletClient + <> cmdNetwork networkClient + <> cmdStakePool stakePoolClient + <> cmdVersion beforeMainLoop :: Trace IO MainLog -> URI -> IO () beforeMainLoop tr = logInfo tr . MsgListenAddress @@ -224,7 +228,8 @@ beforeMainLoop tr = logInfo tr . MsgListenAddress data ServeArgs = ServeArgs { _hostPreference :: HostPreference , _mode :: Mode CardanoNodeConn - , _listen :: Listen + , _listenApi :: Listen + , _listenUi :: Maybe Listen , _tlsConfig :: Maybe TlsConfiguration , _networkConfiguration :: NetworkConfiguration , _database :: Maybe FilePath @@ -232,70 +237,81 @@ data ServeArgs = ServeArgs , _poolMetadataSourceOpt :: Maybe PoolMetadataSource , _tokenMetadataSourceOpt :: Maybe TokenMetadataServer , _logging :: LoggingOptions TracerSeverities - } deriving (Show) + } + deriving (Show) cmdServe :: Mod CommandFields (IO ()) -cmdServe = command "serve" $ info (helper <*> helper' <*> cmd) $ - progDesc "Serve API that listens for commands/actions." +cmdServe = + command "serve" + $ info (helper <*> helper' <*> cmd) + $ progDesc "Serve API that listens for commands/actions." where helper' = helperTracing tracerDescriptions - cmd = fmap exec $ ServeArgs - <$> hostPreferenceOption - <*> modeOption nodeSocketOption - <*> listenOption - <*> optional tlsOption - <*> networkConfigurationOption - <*> optional databaseOption - <*> shutdownHandlerFlag - <*> optional poolMetadataSourceOption - <*> optional tokenMetadataSourceOption - <*> loggingOptions tracerSeveritiesOption + cmd = + fmap exec + $ ServeArgs + <$> hostPreferenceOption + <*> modeOption nodeSocketOption + <*> listenApiOption + <*> listenUiOption + <*> optional tlsOption + <*> networkConfigurationOption + <*> optional databaseOption + <*> shutdownHandlerFlag + <*> optional poolMetadataSourceOption + <*> optional tokenMetadataSourceOption + <*> loggingOptions tracerSeveritiesOption exec :: ServeArgs -> IO () - exec args@(ServeArgs - host - mode - listen - tlsConfig - networkConfig - databaseDir - enableShutdownHandler - poolMetadataFetching - tokenMetadataServerURI - logOpt) = withTracers logOpt $ \tr tracers -> do - withShutdownHandlerMaybe tr enableShutdownHandler $ do - logDebug tr $ MsgServeArgs args + exec + args@( ServeArgs + host + mode + listenApi + listenUi + tlsConfig + networkConfig + databaseDir + enableShutdownHandler + poolMetadataFetching + tokenMetadataServerURI + logOpt + ) = withTracers logOpt $ \tr tracers -> do + withShutdownHandlerMaybe tr enableShutdownHandler $ do + logDebug tr $ MsgServeArgs args - (discriminant, netParams, vData, block0) - <- runExceptT (parseGenesisData networkConfig) >>= \case + (discriminant, netParams, vData, block0) <- + runExceptT (parseGenesisData networkConfig) >>= \case Right x -> pure x Left err -> do logError tr (MsgFailedToParseGenesis $ T.pack err) exitWith $ ExitFailure 33 - forM_ databaseDir $ - setupDirectory (logInfo tr . MsgSetupDatabases) + forM_ databaseDir + $ setupDirectory (logInfo tr . MsgSetupDatabases) - blockchainSource <- case mode of - Normal conn syncTolerance -> - pure $ NodeSource conn vData syncTolerance + blockchainSource <- case mode of + Normal conn syncTolerance -> + pure $ NodeSource conn vData syncTolerance - exitWith =<< serveWallet - blockchainSource - netParams - tunedForMainnetPipeliningStrategy - discriminant - [] - tracers - databaseDir - Nothing - host - listen - tlsConfig - (Settings <$> poolMetadataFetching) - tokenMetadataServerURI - block0 - (beforeMainLoop tr) + exitWith + =<< serveWallet + blockchainSource + netParams + tunedForMainnetPipeliningStrategy + discriminant + [] + tracers + databaseDir + Nothing + host + listenApi + listenUi + tlsConfig + (Settings <$> poolMetadataFetching) + tokenMetadataServerURI + block0 + (beforeMainLoop tr) withShutdownHandlerMaybe :: Trace IO MainLog -> Bool -> IO () -> IO () withShutdownHandlerMaybe _ False = void @@ -323,10 +339,14 @@ data MainLog instance ToText MainLog where toText = \case MsgCmdLine exe args -> - T.pack $ unwords ("Command line:":exe:args) + T.pack $ unwords ("Command line:" : exe : args) MsgVersion ver rev arch os -> - "Running as " <> T.pack (showFullVersion ver rev) <> " on " <> - T.pack arch <> "-" <> T.pack os + "Running as " + <> T.pack (showFullVersion ver rev) + <> " on " + <> T.pack arch + <> "-" + <> T.pack os MsgSetupStateDir txt -> "Wallet state: " <> txt MsgSetupDatabases txt -> @@ -341,14 +361,16 @@ instance ToText MainLog where "Interrupted by user." MsgShutdownHandler msg' -> toText msg' - MsgFailedToParseGenesis hint -> T.unwords - [ "Failed to parse Byron genesis configuration. You may want to check" - , "the filepath given via --genesis and make sure it points to a " - , "valid JSON Byron genesis file. The genesis file must be Byron, not" - , "Shelley as it used to feed the wallet with the initial blockchain" - , "parameters." - , "Here's (perhaps) some helpful hint:", hint - ] + MsgFailedToParseGenesis hint -> + T.unwords + [ "Failed to parse Byron genesis configuration. You may want to check" + , "the filepath given via --genesis and make sure it points to a " + , "valid JSON Byron genesis file. The genesis file must be Byron, not" + , "Shelley as it used to feed the wallet with the initial blockchain" + , "parameters." + , "Here's (perhaps) some helpful hint:" + , hint + ] withTracers :: LoggingOptions TracerSeverities @@ -367,19 +389,22 @@ withTracers logOpt action = action trMain tracers `withException` logInterrupt tracerSeveritiesOption :: Parser TracerSeverities -tracerSeveritiesOption = Tracers - <$> traceOpt applicationTracer (Just Info) - <*> traceOpt apiServerTracer (Just Info) - <*> traceOpt tokenMetadataTracer (Just Info) - <*> traceOpt walletEngineTracer (Just Info) - <*> traceOpt walletDbTracer (Just Info) - <*> traceOpt poolsEngineTracer (Just Info) - <*> traceOpt poolsDbTracer (Just Info) - <*> traceOpt ntpClientTracer (Just Info) - <*> traceOpt networkTracer (Just Info) +tracerSeveritiesOption = + Tracers + <$> traceOpt applicationTracer (Just Info) + <*> traceOpt apiServerTracer (Just Info) + <*> traceOpt tokenMetadataTracer (Just Info) + <*> traceOpt walletEngineTracer (Just Info) + <*> traceOpt walletDbTracer (Just Info) + <*> traceOpt poolsEngineTracer (Just Info) + <*> traceOpt poolsDbTracer (Just Info) + <*> traceOpt ntpClientTracer (Just Info) + <*> traceOpt networkTracer (Just Info) where - traceOpt field def = fmap Const . option loggingSeverityOrOffReader $ mempty - <> long ("trace-" <> T.unpack (getConst (field tracerLabels))) - <> value def - <> metavar "SEVERITY" - <> internal + traceOpt field def = + fmap Const . option loggingSeverityOrOffReader + $ mempty + <> long ("trace-" <> T.unpack (getConst (field tracerLabels))) + <> value def + <> metavar "SEVERITY" + <> internal diff --git a/lib/exe/cardano-wallet-exe.cabal b/lib/exe/cardano-wallet-exe.cabal index 6a5cc3c17c3..2aafa3a9b18 100644 --- a/lib/exe/cardano-wallet-exe.cabal +++ b/lib/exe/cardano-wallet-exe.cabal @@ -21,17 +21,16 @@ common language default-extensions: NoImplicitPrelude OverloadedStrings -common opts-exe - ghc-options: -threaded -rtsopts -Wall -Wredundant-constraints - -Wunused-packages +common opts-exe + ghc-options: + -threaded -rtsopts -Wall -Wredundant-constraints -Wunused-packages if flag(release) ghc-options: -O2 -Werror common opts-lib - ghc-options: -Wall -Wcompat -Wredundant-constraints - -Wunused-packages + ghc-options: -Wall -Wcompat -Wredundant-constraints -Wunused-packages if flag(release) ghc-options: -O2 -Werror @@ -88,6 +87,7 @@ library , cardano-wallet-read , cardano-wallet-secrets , contra-tracer + , data-default , directory , extra , file-embed @@ -104,24 +104,30 @@ library , servant-client , servant-client-core , servant-server + , streaming-commons , template-haskell , text , text-class , time + , tls , transformers , unliftio - , warp , wai-middleware-logging + , warp + , warp-tls , Win32-network + , x509 + , x509-store + , x509-validation exposed-modules: - Cardano.Wallet.Application Cardano.Wallet.Application.CLI + Cardano.Wallet.Application.Logging + Cardano.Wallet.Application.Server + Cardano.Wallet.Application.Tls Cardano.Wallet.Application.Tracers Cardano.Wallet.Application.Version Cardano.Wallet.Application.Version.TH - other-modules: - - Paths_cardano_wallet_exe + other-modules: Paths_cardano_wallet_exe diff --git a/lib/exe/lib/Cardano/Wallet/Application.hs b/lib/exe/lib/Cardano/Wallet/Application.hs index dfb35c35462..9a70e72df18 100644 --- a/lib/exe/lib/Cardano/Wallet/Application.hs +++ b/lib/exe/lib/Cardano/Wallet/Application.hs @@ -59,17 +59,25 @@ import Cardano.Wallet.Api , ApiV2 ) import Cardano.Wallet.Api.Http.Logging - ( ApplicationLog (..) + ( ApiApplicationLog (..) ) import Cardano.Wallet.Api.Http.Server ( server ) import Cardano.Wallet.Api.Http.Shelley.Server - ( HostPreference - , Listen (..) + ( toServerError + ) +import Cardano.Wallet.Application.Logging + ( ApplicationLog (..) + ) +import Cardano.Wallet.Application.Server + ( Listen , ListenError (..) - , TlsConfiguration - , toServerError + , start + , withListeningSocket + ) +import Cardano.Wallet.Application.Tls + ( TlsConfiguration ) import Cardano.Wallet.Application.Tracers as Tracers ( TracerSeverities @@ -166,7 +174,8 @@ import Control.Monad.Trans.Class ( lift ) import Control.Monad.Trans.Cont - ( ContT (ContT) + ( ContT (..) + , callCC , evalContT ) import Control.Monad.Trans.Except @@ -191,6 +200,9 @@ import Data.Maybe import Data.Proxy ( Proxy (..) ) +import Data.Streaming.Network + ( HostPreference + ) import Data.Typeable ( Typeable ) @@ -216,6 +228,9 @@ import System.Exit import System.IOManager ( withIOManager ) +import UnliftIO + ( withAsync + ) import qualified Cardano.Pool.DB.Layer as Pool import qualified Cardano.Wallet.Api.Http.Shelley.Server as Server @@ -248,6 +263,8 @@ serveWallet -- ^ Which host to bind. -> Listen -- ^ HTTP API Server port. + -> Maybe Listen + -- ^ Optional HTTP UI Server port. -> Maybe TlsConfiguration -- ^ An optional TLS configuration -> Maybe Settings @@ -272,7 +289,8 @@ serveWallet databaseDir mPoolDatabaseDecorator hostPref - listen + listenApi + mListenUi tlsConfig settings tokenMetaUri @@ -280,8 +298,12 @@ serveWallet beforeMainLoop = withSNetworkId network $ \sNetwork -> evalContT $ do let netId = networkIdVal sNetwork lift $ case blockchainSource of - NodeSource nodeConn _ _ -> trace $ MsgStartingNode nodeConn + NodeSource nodeConn _ _ -> + trace + $ ApiApplicationLog + $ MsgStartingNode nodeConn lift . trace + $ ApiApplicationLog $ MsgNetworkName $ networkDiscriminantVal sNetwork netLayer <- @@ -311,28 +333,51 @@ serveWallet shelleyApi <- withShelleyApi netId netLayer multisigApi <- withMultisigApi netId netLayer ntpClient <- withNtpClient ntpClientTracer - eSocket <- bindSocket - lift $ case eSocket of - Left err -> do - trace $ MsgServerStartupError err - pure $ ExitFailure $ exitCodeApiServer err - Right (_port, socket) -> do - startServer - sNetwork - socket - randomApi - icarusApi - shelleyApi - multisigApi - stakePoolLayer - ntpClient - pure ExitSuccess + eUiSocket <- bindUiSocket + callCC $ \exit -> do + _ <- case eUiSocket of + Left err -> do + lift $ trace $ MsgServerStartupError err + exit $ ExitFailure $ exitCodeApiServer err + Right ms -> do + case ms of + Nothing -> pure () + Just (_port, socket) -> do + ContT $ \k -> + withAsync (startUiServer socket) $ \_ -> k () + pure ExitSuccess + + eApiSocket <- bindApiSocket + case eApiSocket of + Left err -> do + lift $ trace $ MsgServerStartupError err + exit $ ExitFailure $ exitCodeApiServer err + Right (_port, socket) -> do + lift + $ startApiServer + sNetwork + socket + randomApi + icarusApi + shelleyApi + multisigApi + stakePoolLayer + ntpClient + exit ExitSuccess where trace :: ApplicationLog -> IO () trace = traceWith applicationTracer - bindSocket :: ContT r IO (Either ListenError (Warp.Port, Socket)) - bindSocket = ContT $ Server.withListeningSocket hostPref listen + bindApiSocket :: ContT r IO (Either ListenError (Warp.Port, Socket)) + bindApiSocket = ContT $ withListeningSocket hostPref listenApi + + bindUiSocket :: ContT r IO (Either ListenError (Maybe (Warp.Port, Socket))) + bindUiSocket = case mListenUi of + Nothing -> pure $ Right Nothing + Just listenUi -> do + fmap (fmap Just) + $ ContT + $ withListeningSocket hostPref listenUi withRandomApi netId netLayer = lift @@ -365,7 +410,10 @@ serveWallet netLayer Server.idleWorker - startServer + startUiServer :: Socket -> IO () + startUiServer _socket = pure () -- TODO + + startApiServer :: forall n . ( HasSNetworkId n , Typeable n @@ -379,7 +427,7 @@ serveWallet -> StakePoolLayer -> NtpClient -> IO () - startServer _proxy socket byron icarus shelley multisig spl ntp = do + startApiServer _proxy socket byron icarus shelley multisig spl ntp = do serverUrl <- getServerUrl tlsConfig socket let serverSettings = Warp.defaultSettings @@ -396,7 +444,7 @@ serveWallet spl ntp blockchainSource - Server.start + start serverSettings apiServerTracer tlsConfig diff --git a/lib/exe/lib/Cardano/Wallet/Application/CLI.hs b/lib/exe/lib/Cardano/Wallet/Application/CLI.hs index 3dc8d8453c9..736d0605654 100644 --- a/lib/exe/lib/Cardano/Wallet/Application/CLI.hs +++ b/lib/exe/lib/Cardano/Wallet/Application/CLI.hs @@ -48,7 +48,7 @@ module Cardano.Wallet.Application.CLI , argumentT , databaseOption , hostPreferenceOption - , listenOption + , listenApiOption , shutdownHandlerFlag , stateDirOption , syncToleranceOption @@ -98,6 +98,7 @@ module Cardano.Wallet.Application.CLI , getPrometheusURL , getEKGURL , ekgEnabled + , listenUiOption ) where import Prelude hiding @@ -169,11 +170,7 @@ import Cardano.Wallet.Api.Client , TransactionClient (..) , WalletClient (..) ) -import Cardano.Wallet.Api.Http.Shelley.Server - ( HostPreference - , Listen (..) - , TlsConfiguration (..) - ) + import Cardano.Wallet.Api.Types ( AccountPostData (..) , AddressAmount @@ -323,9 +320,18 @@ import Network.HTTP.Client import Cardano.Wallet.Api.Types.Transaction ( ApiLimit (..) ) +import Cardano.Wallet.Application.Server + ( Listen (..) + ) +import Cardano.Wallet.Application.Tls + ( TlsConfiguration (..) + ) import Cardano.Wallet.Network.RestorationMode ( RestorationMode (..) ) +import Data.Streaming.Network + ( HostPreference + ) import GHC.Num ( Natural ) @@ -1419,12 +1425,35 @@ hostPreferenceOption = option str $ mempty <> showDefaultWith (const "127.0.0.1") -- | [--random-port|--port=INT] -listenOption :: Parser Listen -listenOption = +listenApiOption :: Parser Listen +listenApiOption = (ListenOnRandomPort <$ randomPortOption) <|> (ListenOnPort . getPort <$> portOption) +-- | [--ui-random-port|--ui-port=INT] +listenUiOption :: Parser (Maybe Listen) +listenUiOption = + (Just ListenOnRandomPort <$ uiRandomPortOption) + <|> + (Just . ListenOnPort . getPort <$> uiPortOption) + <|> + pure Nothing + +-- | [--ui-random-port] +uiRandomPortOption :: Parser Bool +uiRandomPortOption = flag' False $ mempty + <> long "ui-random-port" + <> help "serve the wallet UI on any available port (conflicts with --ui-port)" + +-- | [--ui-port=INT] +uiPortOption :: Parser (Port "Wallet UI") +uiPortOption = optionT $ mempty + <> long "ui-port" + <> metavar "INT" + <> help "port used for serving the wallet UI." + <> showDefaultWith showT + -- | [--random-port] randomPortOption :: Parser Bool randomPortOption = flag' False $ mempty diff --git a/lib/exe/lib/Cardano/Wallet/Application/Logging.hs b/lib/exe/lib/Cardano/Wallet/Application/Logging.hs new file mode 100644 index 00000000000..94e2912cafb --- /dev/null +++ b/lib/exe/lib/Cardano/Wallet/Application/Logging.hs @@ -0,0 +1,39 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE LambdaCase #-} + +module Cardano.Wallet.Application.Logging + ( ApplicationLog (..) + ) where + +import Prelude + +import Cardano.BM.Data.Tracer + ( HasPrivacyAnnotation + , HasSeverityAnnotation + ) +import Cardano.Wallet.Api.Http.Logging + ( ApiApplicationLog + ) +import Cardano.Wallet.Application.Server + ( ListenError + ) +import Data.Text.Class + ( ToText (..) + ) +import GHC.Generics + ( Generic + ) + +data ApplicationLog + = ApiApplicationLog ApiApplicationLog + | MsgServerStartupError ListenError + deriving (Generic, Show, Eq) + +instance ToText ApplicationLog where + toText = \case + ApiApplicationLog msg -> toText msg + MsgServerStartupError err -> toText err + +instance HasPrivacyAnnotation ApplicationLog + +instance HasSeverityAnnotation ApplicationLog diff --git a/lib/exe/lib/Cardano/Wallet/Application/Server.hs b/lib/exe/lib/Cardano/Wallet/Application/Server.hs new file mode 100644 index 00000000000..42fa599fe7c --- /dev/null +++ b/lib/exe/lib/Cardano/Wallet/Application/Server.hs @@ -0,0 +1,221 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE TupleSections #-} + +module Cardano.Wallet.Application.Server + ( Listen (..) + , walletListenFromEnv + , start + , withListeningSocket + , ListenError (..) + -- * Re-exported for convenience + , HostPreference + ) where + +import Prelude + +import Cardano.Wallet.Api.Http.Shelley.Server + ( IsServerError (..) + ) +import Cardano.Wallet.Application.Tls + ( TlsConfiguration (..) + , requireClientAuth + ) +import Control.Exception + ( IOException + , bracket + , tryJust + ) +import Control.Monad.IO.Class + ( MonadIO (..) + ) +import Control.Tracer + ( Tracer + ) +import Data.Functor + ( (<&>) + ) +import Data.List + ( isInfixOf + ) +import Data.Streaming.Network + ( HostPreference + , bindPortTCP + , bindRandomPortTCP + ) +import Data.Text + ( Text + ) +import Data.Text.Class + ( ToText (..) + ) +import Network.Socket + ( Socket + , close + ) +import Network.Wai.Handler.Warp + ( Port + ) +import Network.Wai.Middleware.Logging + ( ApiLog + , newApiLoggerSettings + , obfuscateKeys + , withApiLogger + ) +import Network.Wai.Middleware.ServerError + ( handleRawError + ) +import Servant.Server + ( Application + ) +import System.Exit + ( die + ) +import System.IO.Error + ( ioeGetErrorType + , isAlreadyInUseError + , isDoesNotExistError + , isPermissionError + , isUserError + ) + +import qualified Data.Text as T +import qualified Network.Wai.Handler.Warp as Warp +import qualified Network.Wai.Handler.WarpTLS as Warp + +-- | Allow configuring which port the wallet server listen to in an integration +-- setup. Crashes if the variable is not a number. +walletListenFromEnv + :: Show e + => (String -> IO (Maybe (Either e Port))) + -> IO Listen +walletListenFromEnv envFromText = + envFromText "CARDANO_WALLET_PORT" >>= \case + Nothing -> pure ListenOnRandomPort + Just (Right port) -> pure $ ListenOnPort port + Just (Left e) -> die $ show e + +-- | How the server should listen for incoming requests. +data Listen + = -- | Listen on given TCP port + ListenOnPort Port + | -- | Listen on an unused TCP port, selected at random + ListenOnRandomPort + deriving (Show, Eq) + +runSocket :: Socket -> Warp.Settings -> Maybe TlsConfiguration -> Application -> IO () +runSocket socket settings = \case + Nothing -> Warp.runSettingsSocket settings socket + Just tls -> Warp.runTLSSocket (requireClientAuth tls) settings socket + +-- | Start the application server, using the given settings and a bound socket. +start + :: Warp.Settings + -> Tracer IO ApiLog + -> Maybe TlsConfiguration + -> Socket + -> Application + -> IO () +start settings tr tlsConfig socket application = do + logSettings <- newApiLoggerSettings <&> obfuscateKeys (const sensitive) + runSocket socket settings tlsConfig + $ handleRawError (curry toServerError) + $ withApiLogger + tr + logSettings + application + where + sensitive :: [Text] + sensitive = + [ "passphrase" + , "old_passphrase" + , "new_passphrase" + , "mnemonic_sentence" + , "mnemonic_second_factor" + ] + +-- | Run an action with a TCP socket bound to a port specified by the `Listen` +-- parameter. +withListeningSocket + :: HostPreference + -- ^ Which host to bind. + -> Listen + -- ^ Whether to listen on a given port, or random port. + -> (Either ListenError (Port, Socket) -> IO a) + -- ^ Action to run with listening socket. + -> IO a +withListeningSocket hostPreference portOpt = bracket acquire release + where + acquire = tryJust handleErr bindAndListen + -- Note: These Data.Streaming.Network functions also listen on the socket, + -- even though their name just says "bind". + bindAndListen = case portOpt of + ListenOnPort port -> (port,) <$> bindPortTCP port hostPreference + ListenOnRandomPort -> bindRandomPortTCP hostPreference + release (Right (_, socket)) = liftIO $ close socket + release (Left _) = pure () + handleErr = ioToListenError hostPreference portOpt + +data ListenError + = ListenErrorAddressAlreadyInUse (Maybe Port) + | ListenErrorOperationNotPermitted + | ListenErrorHostDoesNotExist HostPreference + | ListenErrorInvalidAddress HostPreference + deriving (Show, Eq) + +instance ToText ListenError where + toText = \case + ListenErrorHostDoesNotExist host -> + mempty + <> "Can't listen on " + <> T.pack (show host) + <> ". It does not exist." + ListenErrorInvalidAddress host -> + mempty + <> "Can't listen on " + <> T.pack (show host) + <> ". Invalid address." + ListenErrorAddressAlreadyInUse mPort -> + mempty + <> "The API server listen port " + <> maybe "(unknown)" (T.pack . show) mPort + <> " is already in use." + ListenErrorOperationNotPermitted -> + mempty + <> "Cannot listen on the given port. " + <> "The operation is not permitted." + +ioToListenError :: HostPreference -> Listen -> IOException -> Maybe ListenError +ioToListenError hostPreference portOpt e + -- A socket is already listening on that address and port + | isAlreadyInUseError e = + Just (ListenErrorAddressAlreadyInUse (listenPort portOpt)) + -- Usually caused by trying to listen on a privileged port + | isPermissionError e = + Just ListenErrorOperationNotPermitted + -- Bad hostname -- Linux and Darwin + | isDoesNotExistError e = + Just (ListenErrorHostDoesNotExist hostPreference) + -- Bad hostname -- Windows + -- WSAHOST_NOT_FOUND, WSATRY_AGAIN, or bind: WSAEOPNOTSUPP + | isUserError e && any hasDescription ["11001", "11002", "10045"] = + Just (ListenErrorHostDoesNotExist hostPreference) + -- Address is valid, but can't be used for listening -- Linux + | show (ioeGetErrorType e) == "invalid argument" = + Just (ListenErrorInvalidAddress hostPreference) + -- Address is valid, but can't be used for listening -- Darwin + | show (ioeGetErrorType e) == "unsupported operation" = + Just (ListenErrorInvalidAddress hostPreference) + -- Address is valid, but can't be used for listening -- Windows + | isOtherError e && any hasDescription ["WSAEINVAL", "WSAEADDRNOTAVAIL"] = + Just (ListenErrorInvalidAddress hostPreference) + -- Listening on an unavailable or privileged port -- Windows + | isOtherError e && hasDescription "WSAEACCESS" = + Just (ListenErrorAddressAlreadyInUse (listenPort portOpt)) + | otherwise = + Nothing + where + listenPort (ListenOnPort port) = Just port + listenPort ListenOnRandomPort = Nothing + + isOtherError ex = show (ioeGetErrorType ex) == "failed" + hasDescription text = text `isInfixOf` show e diff --git a/lib/api/src/Cardano/Wallet/Api/Http/Server/Tls.hs b/lib/exe/lib/Cardano/Wallet/Application/Tls.hs similarity index 98% rename from lib/api/src/Cardano/Wallet/Api/Http/Server/Tls.hs rename to lib/exe/lib/Cardano/Wallet/Application/Tls.hs index a8c16e96df1..d08646dffea 100644 --- a/lib/api/src/Cardano/Wallet/Api/Http/Server/Tls.hs +++ b/lib/exe/lib/Cardano/Wallet/Application/Tls.hs @@ -7,7 +7,7 @@ -- Optional TLS support for mutual client-server authentication on top of a Wai -- application. -module Cardano.Wallet.Api.Http.Server.Tls +module Cardano.Wallet.Application.Tls ( TlsConfiguration (..) , requireClientAuth ) where diff --git a/lib/exe/lib/Cardano/Wallet/Application/Tracers.hs b/lib/exe/lib/Cardano/Wallet/Application/Tracers.hs index 349e206822d..bb2c9b4711f 100644 --- a/lib/exe/lib/Cardano/Wallet/Application/Tracers.hs +++ b/lib/exe/lib/Cardano/Wallet/Application/Tracers.hs @@ -39,12 +39,12 @@ import Cardano.BM.Tracing import Cardano.Pool.DB.Log ( PoolDbLog ) -import Cardano.Wallet.Api.Http.Logging - ( ApplicationLog - ) import Cardano.Wallet.Api.Http.Shelley.Server ( WalletEngineLog ) +import Cardano.Wallet.Application.Logging + ( ApplicationLog + ) import Cardano.Wallet.DB.Layer ( DBFactoryLog ) diff --git a/lib/integration/framework/Test/Integration/Framework/Setup.hs b/lib/integration/framework/Test/Integration/Framework/Setup.hs index 527f373518a..b98e0167e0e 100644 --- a/lib/integration/framework/Test/Integration/Framework/Setup.hs +++ b/lib/integration/framework/Test/Integration/Framework/Setup.hs @@ -38,9 +38,6 @@ import Cardano.Startup ( installSignalHandlersNoLogging , setDefaultFilePermissions ) -import Cardano.Wallet.Api.Http.Shelley.Server - ( walletListenFromEnv - ) import Cardano.Wallet.Api.Types ( ApiPoolSpecifier (..) , ApiT (..) @@ -57,6 +54,9 @@ import Cardano.Wallet.Application.CLI , getEKGURL , getPrometheusURL ) +import Cardano.Wallet.Application.Server + ( walletListenFromEnv + ) import Cardano.Wallet.Faucet ( FaucetM , runFaucetM @@ -392,6 +392,7 @@ onClusterStart listen Nothing Nothing + Nothing (Just tokenMetaUrl) block0 (\uri -> k (networkParameters, uri)) diff --git a/lib/unit/cardano-wallet-unit.cabal b/lib/unit/cardano-wallet-unit.cabal index 33353cce722..90ed2994876 100644 --- a/lib/unit/cardano-wallet-unit.cabal +++ b/lib/unit/cardano-wallet-unit.cabal @@ -45,11 +45,11 @@ library test-common , base , bytestring , cardano-api + , cardano-balance-tx:internal , cardano-wallet , cardano-wallet-network-layer , cardano-wallet-primitive , cardano-wallet-read - , cardano-balance-tx:internal , containers , time @@ -73,18 +73,20 @@ test-suite unit , bech32-th , bytestring , cardano-addresses + , cardano-api , cardano-api-extra - , cardano-api:{cardano-api, internal} - , cardano-balance-tx:{cardano-balance-tx, internal} + , cardano-api:internal + , cardano-balance-tx + , cardano-balance-tx:internal , cardano-crypto , cardano-crypto-class - , cardano-ledger-core , cardano-ledger-alonzo , cardano-ledger-babbage , cardano-ledger-core , cardano-ledger-shelley , cardano-sl-x509 , cardano-slotting + , cardano-wallet , cardano-wallet-api , cardano-wallet-application-extras , cardano-wallet-exe @@ -95,7 +97,7 @@ test-suite unit , cardano-wallet-secrets , cardano-wallet-test-utils , cardano-wallet-unit:test-common - , cardano-wallet:{cardano-wallet, mock-token-metadata} + , cardano-wallet:mock-token-metadata , cborg , connection , containers @@ -108,7 +110,7 @@ test-suite unit , delta-types , directory , either - , extra >=1.6.17 + , extra >=1.6.17 , file-embed , filepath , fmt @@ -117,8 +119,8 @@ test-suite unit , generic-lens , generics-sop , hedgehog-corpus - , hspec >=2.8.2 - , hspec-core >=2.8.2 + , hspec >=2.8.2 + , hspec-core >=2.8.2 , http-api-data , http-client , http-client-tls @@ -153,7 +155,7 @@ test-suite unit , QuickCheck , quickcheck-classes , quickcheck-instances - , quickcheck-state-machine >=0.6.0 + , quickcheck-state-machine >=0.6.0 , random , regex-pcre-builtin , resourcet @@ -205,10 +207,10 @@ test-suite unit Cardano.Wallet.Address.DiscoverySpec Cardano.Wallet.Address.PoolSpec Cardano.Wallet.Api.Malformed - Cardano.Wallet.Api.Server.TlsSpec Cardano.Wallet.Api.ServerSpec Cardano.Wallet.Api.TypesSpec Cardano.Wallet.ApiSpec + Cardano.Wallet.Application.TlsSpec Cardano.Wallet.Balance.Migration.PlanningSpec Cardano.Wallet.Balance.Migration.SelectionSpec Cardano.Wallet.Balance.MigrationSpec diff --git a/lib/unit/test/unit/Cardano/Wallet/Api/ServerSpec.hs b/lib/unit/test/unit/Cardano/Wallet/Api/ServerSpec.hs index b07c5479a7a..98f99c39995 100644 --- a/lib/unit/test/unit/Cardano/Wallet/Api/ServerSpec.hs +++ b/lib/unit/test/unit/Cardano/Wallet/Api/ServerSpec.hs @@ -25,17 +25,19 @@ import Cardano.Slotting.Slot ) import Cardano.Wallet.Api.Http.Shelley.Server ( IsServerError (..) - , Listen (..) - , ListenError (..) , getNetworkClock , getNetworkInformation , liftHandler - , withListeningSocket ) import Cardano.Wallet.Api.Types ( ApiNetworkInformation (..) , ApiWalletMode (..) ) +import Cardano.Wallet.Application.Server + ( Listen (..) + , ListenError (..) + , withListeningSocket + ) import Cardano.Wallet.DB.Errors ( ErrNoSuchWallet (..) ) diff --git a/lib/unit/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs b/lib/unit/test/unit/Cardano/Wallet/Application/TlsSpec.hs similarity index 97% rename from lib/unit/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs rename to lib/unit/test/unit/Cardano/Wallet/Application/TlsSpec.hs index ff98034b14b..02fc3515a9a 100644 --- a/lib/unit/test/unit/Cardano/Wallet/Api/Server/TlsSpec.hs +++ b/lib/unit/test/unit/Cardano/Wallet/Application/TlsSpec.hs @@ -4,17 +4,19 @@ {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} -module Cardano.Wallet.Api.Server.TlsSpec +module Cardano.Wallet.Application.TlsSpec ( spec ) where import Prelude -import Cardano.Wallet.Api.Http.Shelley.Server +import Cardano.Wallet.Application.Server ( Listen (..) - , TlsConfiguration (..) , withListeningSocket ) +import Cardano.Wallet.Application.Tls + ( TlsConfiguration (..) + ) import Cardano.X509.Configuration ( CertDescription (..) , ConfigurationKey (..) @@ -123,7 +125,7 @@ import UnliftIO.Exception ( fromException ) -import qualified Cardano.Wallet.Api.Http.Shelley.Server as Server +import qualified Cardano.Wallet.Application.Server as Server import qualified Data.ByteString as BS import qualified Network.HTTP.Types.Status as Http import qualified Network.Wai as Wai diff --git a/run/common/nix/run.sh b/run/common/nix/run.sh index fac25d1ae1c..181213b2a15 100755 --- a/run/common/nix/run.sh +++ b/run/common/nix/run.sh @@ -1,4 +1,4 @@ -#! /usr/bin/env -S nix shell '.#cardano-wallet' '.#cardano-node' --command bash +#! /usr/bin/env -S nix shell '.#cardano-wallet' '.#cardano-node' '.#cardano-cli' --command bash # shellcheck shell=bash set -euo pipefail @@ -6,6 +6,7 @@ set -euo pipefail usage() { echo "Usage: $0 [sync]" echo " sync: Sync the service and wait for it to be ready" + echo " start: Start node and wallet services" } # Check if no arguments are provided and display usage if true if [ $# -eq 0 ]; then @@ -20,6 +21,8 @@ source .env RANDOM_PORT=$(shuf -i 2000-65000 -n 1) WALLET_PORT=${WALLET_PORT:=$RANDOM_PORT} +mkdir -p ./databases + # Define a local db if WALLET_DB is not set if [[ -z "${WALLET_DB-}" ]]; then LOCAL_WALLET_DB=./databases/wallet-db @@ -28,6 +31,10 @@ if [[ -z "${WALLET_DB-}" ]]; then export WALLET_DB fi +if [[ -n "${CLEANUP_DB-}" ]]; then + rm -rf "${WALLET_DB:?}"/* +fi + # Define a local db if NODE_DB is not set if [[ -z "${NODE_DB-}" ]]; then LOCAL_NODE_DB=./databases/node-db @@ -36,11 +43,17 @@ if [[ -z "${NODE_DB-}" ]]; then export NODE_DB fi +if [[ -n "${CLEANUP_DB-}" ]]; then + rm -rf "${NODE_DB:?}"/* +fi + +NETWORK=${NETWORK:=testnet} + # Define and export the node socket name NODE_SOCKET_NAME=node.socket # Define and export the local and actual directory for the node socket -LOCAL_NODE_SOCKET_DIR=./. +LOCAL_NODE_SOCKET_DIR=./databases NODE_SOCKET_DIR=${NODE_SOCKET_DIR:=$LOCAL_NODE_SOCKET_DIR} NODE_SOCKET_PATH=${NODE_SOCKET_DIR}/${NODE_SOCKET_NAME} @@ -64,20 +77,35 @@ cardano-node run \ +RTS -N -A16m -qg -qb -RTS 1>$NODE_LOGS_FILE 2>$NODE_LOGS_FILE & NODE_ID=$! +sleep 3 + +cardano-cli ping -u "${NODE_SOCKET_PATH}" + +echo "Node id: $NODE_ID" + # Define the wallet logs file LOCAL_WALLET_LOGS_FILE=./wallet.log WALLET_LOGS_FILE="${WALLET_LOGS_FILE:=$LOCAL_WALLET_LOGS_FILE}" -# Start the wallet with logs redirected to a file if WALLET_LOGS_FILE is set -# shellcheck disable=SC2086 -cardano-wallet serve \ - --port "${WALLET_PORT}" \ - --database "${WALLET_DB}" \ - --node-socket "${NODE_SOCKET_PATH}" \ - --testnet "${NODE_CONFIGS}"/byron-genesis.json \ - --listen-address 0.0.0.0 1>$WALLET_LOGS_FILE 2>$WALLET_LOGS_FILE & -WALLET_ID=$! - +if [[ "${NETWORK}" == "mainnet" ]]; then + # shellcheck disable=SC2086 + cardano-wallet serve \ + --port "${WALLET_PORT}" \ + --database "${WALLET_DB}" \ + --node-socket "${NODE_SOCKET_PATH}" \ + --mainnet \ + --listen-address 0.0.0.0 1>$WALLET_LOGS_FILE 2>$WALLET_LOGS_FILE & + WALLET_ID=$! +else + # shellcheck disable=SC2086 + cardano-wallet serve \ + --port "${WALLET_PORT}" \ + --database "${WALLET_DB}" \ + --node-socket "${NODE_SOCKET_PATH}" \ + --testnet "${NODE_CONFIGS}"/byron-genesis.json \ + --listen-address 0.0.0.0 1>$WALLET_LOGS_FILE 2>$WALLET_LOGS_FILE & + WALLET_ID=$! +fi cleanup() { echo "Cleaning up..." @@ -134,6 +162,13 @@ case "$1" in exit 1 fi ;; + start) + echo "Wallet service port: $WALLET_PORT" + echo "Node socket path: $NODE_SOCKET_PATH" + echo "Wallet pid: $WALLET_ID" + echo "Node pid: $NODE_ID" + trap - ERR INT EXIT + ;; *) echo "Error: Invalid option $1" usage