Skip to content

Conversation

@the-headless-ghost
Copy link
Member

@the-headless-ghost the-headless-ghost commented Nov 8, 2025

Description

Closes #4381

Checklist

Quality

  • Commit sequence makes sense and have useful messages, see ref.
  • New tests are added and existing tests are updated.
  • Self-reviewed the PR.

Maintenance

  • Linked an issue or added the PR to the current sprint of ouroboros-network project.
  • Added labels.
  • Updated changelog files.
  • The documentation has been properly updated, see ref.

@the-headless-ghost the-headless-ghost changed the title Peers behind the firewall Peers behind a firewall Nov 10, 2025
-- ^ True if peer is not behind a firewall
<$> readLocalRootPeers

peerconn <- establishPeerConnection isBigLedgerPeer diffusionMode peeraddr connectionMode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename connectionMode to provenance.

-> DiffusionMode
-> peeraddr -> m peerconn,
-> peeraddr
-> ConnectionMode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Provenance here instead.

Comment on lines 1491 to 1493
when (inboundRequired connectionMode) $
throwIO (withCallStack $ InboundConnectionNotFound peerAddr)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The damage is done by the time you do this check. A few lines above in the Nothing case we have updated the stateVar by inserting this outbound connection into the CM's connection table.

Comment on lines +75 to +80
localRootsToRelayAccessPoint
:: LocalRoots
-> [(RelayAccessPoint, PeerAdvertise, Bool)]
localRootsToRelayAccessPoint LocalRoots {rootConfig, behindFirewall} =
(\(accessPoint, advertise) -> (accessPoint, advertise, behindFirewall))
<$> rootConfigToRelayAccessPoint rootConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's needed.

extraLocalRootFlags :: !extraFlags
peerAdvertise :: !PeerAdvertise,
diffusionMode :: !DiffusionMode,
localRootBehindFirewall :: !Bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this type to Provenance?

Copy link
Collaborator

@coot coot Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also avoid boolean blindness 😄, but it still should be a Boolean value in json.

IsTrustable -> not
. null
. rootAccessPoints
. rootConfig
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's needed - see my other comments.


type AcquireOutboundConnection peerAddr handle handleError m
= DiffusionMode -> peerAddr -> m (Connected peerAddr handle handleError)
= DiffusionMode -> peerAddr -> ConnectionMode -> m (Connected peerAddr handle handleError)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/ConnectionMode/Provenance/

Comment on lines 744 to 745
--
| InboundConnectionNotFound !peerAddr !CallStack
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be a typical case where an inbound is not found for behind firewall peers. Maybe instead create the opposite trace where we inform that we are establishing a connection back to a peer of 'inbound' provenance?

@the-headless-ghost
Copy link
Member Author

@crocodile-dentist I’m not sure the Provenance type is the right choice, as the comments indicate that its interpretation refers to connections initiated either locally or by a remote peer, but not both. However, what we need is a way to specify connections that are either initiated only by a remote peer or initiated in any way—locally or remotely.

@crocodile-dentist
Copy link
Contributor

What I had in mind was a little overloading of the meaning of provenance. So jobPromoteColdPeer would be passed this type Provenance and we could name the binding as demandedProvenance or somesuch, which would be Inbound for those peers we marked as being 'behind firewall' in the topology file. In other cases, it would be Outbound. The CM code would have our special handling for those outbound connections for which we demand there is an inbound for, and otherwise it is a plain request for acquiring an outbound connection, so the Outbound value makes sense as well, and the handling is as before. We can change the haddock around the Provenance type to better explain this intent. This has the benefit of not polluting our namespace with another kind of a boolean. If this type you're trying to introduce was more meaningful, then I'd agree with what you're saying.

@the-headless-ghost the-headless-ghost marked this pull request as ready for review November 17, 2025 10:58
@the-headless-ghost the-headless-ghost requested a review from a team as a code owner November 17, 2025 10:58
Copy link
Collaborator

@coot coot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @crocodile-dentist that we could use Provenance instead of ConnectionMode. But it would be good to ask @karknu if he agrees with the terminology, since it might be a bit surprising for an SPO.

A few other comments & suggestions follow.

Comment on lines +513 to +515
inboundRequired :: ConnectionMode -> Bool
inboundRequired RequireInbound = True
inboundRequired _other = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is unnecessary indirection, we can directly pattern match on the constructors.

Comment on lines +1471 to +1475
return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr))
, mutableConnState
, Left (withCallStack
(InboundConnectionNotFound connectionMode peerAddr))
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style:

Suggested change
return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr))
, mutableConnState
, Left (withCallStack
(InboundConnectionNotFound connectionMode peerAddr))
)
return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr))
, mutableConnState
, Left (withCallStack
(InboundConnectionNotFound connectionMode peerAddr))
)

if inboundRequired connectionMode
then do
return ( Just (Right (TrInboundConnectionNotFound connectionMode peerAddr))
, mutableConnState
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not point in returning mutableConnState (this branch of if should not executed newMutableConnState as it must not be used, which requries a bit more refactoring.

Comment on lines +1473 to +1474
, Left (withCallStack
(InboundConnectionNotFound connectionMode peerAddr))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to find out if throwing an exception in this case is right or should we return an explicit value. After a deliberation, I think it's fine to do so (and thus throw an exception). The outbound governor is not supposed to call establishPeerConnection unless there already is an inbound connection for such a peer. So if we find InboundConnectionNotFound in the logs, it's actually a signal for us to debug it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There could be a race condition here, but maybe throwing an exception is still a convenient way of dealing with it anyway.

extraLocalRootFlags :: !extraFlags
peerAdvertise :: !PeerAdvertise,
diffusionMode :: !DiffusionMode,
localRootBehindFirewall :: !Bool,
Copy link
Collaborator

@coot coot Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will also avoid boolean blindness 😄, but it still should be a Boolean value in json.

Comment on lines +82 to +84
-- Note: Some peers may be behind a firewall. Local root peers marked as
-- behind a firewall are not excluded from this list.
--
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the note.

Comment on lines +2901 to +2906
isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) =
localRootBehindFirewall
unreachablePeers =
Map.keysSet
$ Map.filter isUnreachablePeer
$ LocalRootPeers.toMap local
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
isUnreachablePeer (LocalRootConfig {localRootBehindFirewall}) =
localRootBehindFirewall
unreachablePeers =
Map.keysSet
$ Map.filter isUnreachablePeer
$ LocalRootPeers.toMap local
unreachablePeers =
Map.keysSet
$ Map.filter localRootBehindFirewall
$ LocalRootPeers.toMap local

Comment on lines +2931 to +2933
((,,) <$> govLocalRootPeersSig
<*> govUnreachablePeersSig
<*> govInboundConnectionsSig)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code style

Suggested change
((,,) <$> govLocalRootPeersSig
<*> govUnreachablePeersSig
<*> govInboundConnectionsSig)
((,,) <$> govLocalRootPeersSig
<*> govUnreachablePeersSig
<*> govInboundConnectionsSig)

Comment on lines +2911 to +2912
govInboundConnectionsSig :: Signal (Set NtNAddr)
govInboundConnectionsSig =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
govInboundConnectionsSig :: Signal (Set NtNAddr)
govInboundConnectionsSig =
-- all connections which triggered `TrConnectionNotFound Inbound`
govNotFoundInboundConnSig :: Signal (Set NtNAddr)
govNotFoundInboundConnSig =

Comment on lines +103 to +105
<$> (RootConfig
<$> o .: "accessPoints"
<*> o .:? "advertise" .!= DoNotAdvertisePeer)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have a FromJSON instance for RootConfig that can be used here?

@karknu
Copy link
Contributor

karknu commented Nov 28, 2025

I agree with @crocodile-dentist that we could use Provenance instead of ConnectionMode. But it would be good to ask @karknu if he agrees with the terminology, since it might be a bit surprising for an SPO.

A few other comments & suggestions follow.

I agree with @crocodile-dentist .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration connection-manager Issues / PRs related to connection-manager

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Optimised connectivity to peers behind firewall

5 participants