ouroboros-network-0.16.0.0: A networking layer for the Ouroboros blockchain protocol
Safe HaskellSafe-Inferred
LanguageHaskell2010

Ouroboros.Network.PeerSelection.PeerStateActions

Synopsis

Introduction

This module implements withPeerStateActions, giving the user access to the PeerStateActions API, which provides the following capabilities:

synchronous promotions / demotions
* establishPeerConnection * activatePeerConnection * deactivatePeerConnection * closePeerConnection
monitoring
monitorPeerConnection - returns the state of the connection.
asynchronous demotions
happens when a mini-protocol terminates or errors.

Synchronous promotions / demotions

Synchronous promotions / demotions are used by peerSelectionGovernor.

synchronous cold → warm transition
This transition starts with creating or reusing an inbound connection, do handshake (functionality provided by connection manager), start established and warm mini-protocols, start monitoring thread specified below.
synchronous warm → hot transition
This transition quiesces warm protocols and starts hot protocols. There is no timeout to quiesce warm mini-protocols. The tip-sample protocol which is the only planned warm protocol has some states that have a longer timeout when the remote peer has agency, but it does not transfer much data.
synchronous hot → warm transition
Within a timeout, stop hot protocols and let the warm protocols continue running. If the timeout expires the connection is closed. Note that this will impact inbound side of a duplex connection. We cannot do any better: closing is a cooperative action since we require to arrive at a well defined state of the multiplexer (no outstanding data in ingress queue). This transition must use last to finish synchronisation of all hot mini-protocols.
synchronous warm → cold transition
Shutdown established and warm protocols. As in the previous transition it must use last to finish synchronisation on established and warm protocol termination, if this synchronisation timeouts the connection is closed.

Monitoring Loop

The monitoring loop is responsible for taking an action when one of the mini-protocols either terminates or errors. When a mini-protocol terminates

  • if (mini-protocol was hot): trigger a synchronous hot → warm transition.
  • otherwise: close the connection.

The monitoring loop is supposed to stop when the multiplexer stops.

Note that the monitoring loop must act as soon as one of the mini-protocols terminates or errors, hence the use of first to finish synchronisation.

The multiplexer guarantees that whenever one of the mini-protocols errors the connection is closed. This simplifies the actions needed to be taken by the monitoring loop.

Asynchronous demotions

asynchronous * → cold transition
This demotion is triggered whenever any of the mini-protocol errors. This does not require a further action by the monitoring loop: mux will close the connection, monitoring loop will terminate.
asynchronous hot → warm demotion
This demotion is triggered if a hot mini-protocol terminates cleanly. In this case we trigger synchronous hot → warm demotion which will halt all hot mini-protocols and will notify the peer-to-peer governor about the change.

Implementation details

PeerStateActions are build on top of ConnectionManager which provides a primitive to present us a negotiated connection (i.e. after running the handshake) and the multiplexer api which allows to start mini-protocols and track their termination via an STM interface. Each connection has an associated PeerConnectionHandle which holds all the data associated with a connection.

Most important are pchMux :: Mux mode m which allows us to interact with the multiplexer and pchAppHandles. The latter contains information about each mini-protocol and its STM mini-protocol monitoring action. ahMiniProtocolResults allows us to build last-to-finish awaitAllResults and first-to-finish awaitFirstResult synchronisations that we need in synchronous transitions and monitoring loop respectively.

ahControlVar is a per-temperature TVar which holds ControlMessage. It is passed from ConnectionHandler via Handle. This variable allows us to terminate, quiesce or re-enable mini-protocols.

Below is a schematic illustration of function calls / threads and shared state variables. Reads done just make assertions are not included. The diagram does not include establishPeerConnection.

Legend: ─  - functions
        │░ - threads
        ━  - STM mutable variables

        ├──▶┃ - write to a TVar
        │◀──┨ - read from a TVar
        ├──▶│ - function call

        PeerStateVar        - 'pchPeerStatus' 'TVar'
        MiniProtocolResults - 'ahMiniProtocolResults' 'TVar'
        ControlVar          - 'ahControlVar' 'TVar'




                    ┌──────────────────────────────────────────┐
                    │ ┌────────┐                               │
                    │ │        │                               │
   ┌────────────────┴─┴─┐      │                               │
  ┌────────────────────┐│      ▼                               ▼
 ┌────────────────────┐││   ┌──────────────────────────┐     ┌─────────────────────┐
 │░░░░░░░░░░░░░░░░░░░░│││   │                          │     │                     │
 │░peerMonitoringLoop░││┘   │ deactivatePeerConnection │     │ closePeerConnection │
 │░░░░░░░░░░░░░░░░░░░░│┘    │                          │     │                     │
 └┬───────────────────┘     └┬────────────────────┬────┘     └───────┬─────────────┘
  │     ▲                    │   ▲                │              ▲ ▲ │
  │ ┌───┼────────────────────┘   │                │              │ │ │
  │ │ ┌─┼────────────────────────┼────────────────┼──────────────┘ │ │
  │ │ │ │                        │     ┌──────────┼────────────────┘ │
  │ │ │ │                        │     │          │ ┌────────────────┘
▒▒│▒│▒│▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒│▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒ │ │ │ └───────────────┐        │     │          │ │                       ▒▒▒
▒ ▼ ▼ ▼                 │        │     │          ▼ ▼                       ▒ ▒▒▒
▒┏━━━━━━━━━━━━━━┓      ┏┷━━━━━━━━┷━━━━━┷┓     ┏━━━━━━━━━━━━━━━━┓            ▒ ▒ ▒
▒┃              ┃┓     ┃                ┃┓    ┃                ┃┓           ▒ ▒ ▒
▒┃ PeerStateVar ┃┃┓    ┃  MiniProtocol  ┃┃┓   ┃  ControlVar    ┃┃┓          ▒ ▒ ▒
▒┃              ┃┃┃    ┃     Results    ┃┃┃   ┃  - established ┃┃┃          ▒ ▒ ▒
▒┃              ┃┃┃    ┃  - established ┃┃┃   ┃  - warm        ┃┃┃          ▒ ▒ ▒
▒┗━━━━━━━━━━━━━━┛┃┃    ┃  - warm        ┃┃┃   ┃  - hot         ┃┃┃          ▒ ▒ ▒
▒ ┗━━━━━━━━━━━━━━┛┃    ┃  - hot         ┃┃┃   ┃                ┃┃┃          ▒ ▒ ▒
▒  ┗━━━━━━━━━━━━━━┛    ┃                ┃┃┃   ┃                ┃┃┃          ▒ ▒ ▒
▒  ▲                   ┗━━━━━━━━━━━━━━━━┛┃┃   ┗━━━━━━━━━━━━━━━━┛┃┃          ▒ ▒ ▒
▒  │                    ┗━━━━━━━━━━━━━━━━┛┃    ┗━━━━━━━━━━━━━━━━┛┃          ▒ ▒ ▒
▒  │                     ┗━━━━━━━━━━━━━━━━┛     ┗━━━━━━━━━━━━━━━━┛          ▒ ▒ ▒
▒  │                                             ▲                          ▒ ▒ ▒
▒  │                   PeerConnectionHandles     │                          ▒ ▒ ▒
▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒ ▒
 ▒ │                                             │                            ▒ ▒
 ▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒
  ▒│                                             │                              ▒
  ▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒│▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
   │                   ┌─────────────────────────┘
 ┌─┴───────────────────┴──┐
 │                        │
 │ activatePeerConnection │
 │                        │
 └────────────────────────┘

Notes:

All three upper boxes: peerMonitoringLoop, deactivatePeerConnection and closePeerConnection are reading ahMiniProtocolResults via the last-to-finish awaitAllResults synchronisation.

All of the thin boxes are writing to pchPeerStatus variable; which is read by 'monitorPeerConnection. Also all of them writing to ahControlVar: peerMonitoringLoop does that through a call to deactivePeerConnection or closePeerConnection.

data PeerStateActionsArguments muxMode socket responderCtx peerAddr versionData versionNumber m a b Source #

Record of arguments of peerSelectionActions.

Constructors

PeerStateActionsArguments 

Fields

data PeerConnectionHandle (muxMode ∷ MuxMode) responderCtx peerAddr versionData bytes m a b Source #

Each established connection has access to PeerConnectionHandle. It allows to promote / demote or close the connection, by having access to Mux, three bundles of miniprotocols: for hot, warm and established peers together with their state StrictTVars.

Instances

Instances details
(Show peerAddr, Show versionData) ⇒ Show (PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Methods

showsPrecIntPeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b → ShowS #

showPeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b → String #

showList ∷ [PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b] → ShowS #

withPeerStateActions ∷ ∀ (muxMode ∷ MuxMode) socket responderCtx peerAddr versionData versionNumber m a b x. (Alternative (STM m), MonadAsync m, MonadCatch m, MonadLabelledSTM m, MonadMask m, MonadTimer m, MonadThrow (STM m), HasInitiator muxMode ~ True, Typeable versionNumber, Show versionNumber, Ord peerAddr, Typeable peerAddr, Show peerAddr) ⇒ PeerStateActionsArguments muxMode socket responderCtx peerAddr versionData versionNumber m a b → (PeerStateActions peerAddr (PeerConnectionHandle muxMode responderCtx peerAddr versionData ByteString m a b) m → m x) → m x Source #

pchPeerSharing ∷ (versionData → PeerSharing) → PeerConnectionHandle muxMode responderCtx peerAddr versionData bytes m a b → PeerSharing Source #

Exceptions

data EstablishConnectionException versionNumber Source #

Constructors

ClientException !(HandshakeException versionNumber)

Handshake client failed

ServerException !(HandshakeException versionNumber)

Handshake server failed

Instances

Instances details
(Show versionNumber, Typeable versionNumber) ⇒ Exception (EstablishConnectionException versionNumber) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Show versionNumber ⇒ Show (EstablishConnectionException versionNumber) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Methods

showsPrecIntEstablishConnectionException versionNumber → ShowS #

showEstablishConnectionException versionNumber → String #

showList ∷ [EstablishConnectionException versionNumber] → ShowS #

Trace

data PeerSelectionActionsTrace peerAddr vNumber Source #

Traces produced by peerSelectionActions.

Instances

Instances details
(Show peerAddr, Show vNumber) ⇒ Show (PeerSelectionActionsTrace peerAddr vNumber) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Methods

showsPrecIntPeerSelectionActionsTrace peerAddr vNumber → ShowS #

showPeerSelectionActionsTrace peerAddr vNumber → String #

showList ∷ [PeerSelectionActionsTrace peerAddr vNumber] → ShowS #

data PeerStatusChangeType peerAddr Source #

All transitions.

Constructors

ColdToWarm

During the ColdToWarm transition we have the remote address, and only if establishing connection (establishing bearer & handshake negotiation) is successful we have access to full ConnectionId.

Fields

  • !(Maybe peerAddr)

    local peer address

  • !peerAddr

    remote peer address

WarmToHot !(ConnectionId peerAddr) 
HotToWarm !(ConnectionId peerAddr) 
WarmToCooling !(ConnectionId peerAddr) 
HotToCooling !(ConnectionId peerAddr) 
CoolingToCold !(ConnectionId peerAddr) 

Instances

Instances details
Show peerAddr ⇒ Show (PeerStatusChangeType peerAddr) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Methods

showsPrecIntPeerStatusChangeType peerAddr → ShowS #

showPeerStatusChangeType peerAddr → String #

showList ∷ [PeerStatusChangeType peerAddr] → ShowS #

data FailureType versionNumber Source #

Type of failure with additional exception context; We don't log handshake errors as this will be done by the handshake tracer.

Instances

Instances details
Show versionNumber ⇒ Show (FailureType versionNumber) Source # 
Instance details

Defined in Ouroboros.Network.PeerSelection.PeerStateActions

Methods

showsPrecIntFailureType versionNumber → ShowS #

showFailureType versionNumber → String #

showList ∷ [FailureType versionNumber] → ShowS #