1- package node
1+ package connectivity
22
33import (
44 "context"
@@ -13,9 +13,9 @@ import (
1313
1414 "github.com/urfave/cli"
1515
16- "github.com/rocket-pool/smartnode/shared/services"
1716 "github.com/rocket-pool/smartnode/shared/services/alerting"
18- "github.com/rocket-pool/smartnode/shared/services/config"
17+ cfg "github.com/rocket-pool/smartnode/shared/services/config"
18+ cfgtypes "github.com/rocket-pool/smartnode/shared/types/config"
1919 "github.com/rocket-pool/smartnode/shared/utils/log"
2020)
2121
@@ -36,36 +36,45 @@ var publicIPResolvers = []struct {
3636}
3737
3838// Check port connectivity task
39- type checkPortConnectivity struct {
39+ type CheckPortConnectivity struct {
4040 c * cli.Context
4141 log log.ColorLogger
42- cfg * config .RocketPoolConfig
42+ cfg * cfg .RocketPoolConfig
4343
4444 // Track previous state to avoid flooding with repeated alerts
4545 wasEth1PortOpen bool
4646 wasBeaconP2POpen bool
47+
48+ // Function pointers for network and alerting actions (to facilitate testing)
49+ getPublicIP func () (string , error )
50+ isPortReachableNATReflection func (string , uint16 ) bool
51+ isPortReachableExternalService func (uint16 ) (bool , string , error )
52+ alertEth1P2PPortNotOpen func (* cfg.RocketPoolConfig , uint16 ) error
53+ alertBeaconP2PPortNotOpen func (* cfg.RocketPoolConfig , uint16 ) error
4754}
4855
4956// Create check port connectivity task
50- func newCheckPortConnectivity (c * cli.Context , logger log.ColorLogger ) (* checkPortConnectivity , error ) {
51- cfg , err := services .GetConfig (c )
52- if err != nil {
53- return nil , err
54- }
55-
56- return & checkPortConnectivity {
57+ func NewCheckPortConnectivity (c * cli.Context , config * cfg.RocketPoolConfig , logger log.ColorLogger ) (* CheckPortConnectivity , error ) {
58+ return & CheckPortConnectivity {
5759 c : c ,
5860 log : logger ,
59- cfg : cfg ,
61+ cfg : config ,
6062 // Assume ports are open at startup to avoid spurious alerts on first cycle
6163 wasEth1PortOpen : true ,
6264 wasBeaconP2POpen : true ,
65+
66+ // Default implementations
67+ getPublicIP : getPublicIP ,
68+ isPortReachableNATReflection : isPortReachableNATReflection ,
69+ isPortReachableExternalService : isPortReachableExternalService ,
70+ alertEth1P2PPortNotOpen : alerting .AlertEth1P2PPortNotOpen ,
71+ alertBeaconP2PPortNotOpen : alerting .AlertBeaconP2PPortNotOpen ,
6372 }, nil
6473}
6574
6675// Check whether the configured execution/consensus client P2P ports are
6776// reachable from the internet. Sends an alert the first time either port is detected as closed.
68- func (t * checkPortConnectivity ) run () error {
77+ func (t * CheckPortConnectivity ) Run () error {
6978 if t .cfg .Alertmanager .EnableAlerting .Value != true {
7079 return nil
7180 }
@@ -74,18 +83,27 @@ func (t *checkPortConnectivity) run() error {
7483 }
7584 t .log .Print ("Checking port connectivity..." )
7685
86+ // EC and CC are always both local or both external - mixed configurations are rejected during validation.
87+ // We don't check external clients because the node operator is responsible for their
88+ // connectivity, and they may be behind a different firewall or NAT entirely.
89+ isLocalMode := t .cfg .ExecutionClientMode .Value .(cfgtypes.Mode ) == cfgtypes .Mode_Local
90+ if ! isLocalMode {
91+ return nil
92+ }
93+
7794 ecOpen := false
7895 ccOpen := false
7996 ecP2PPort := t .cfg .ExecutionCommon .P2pPort .Value .(uint16 )
8097 ccP2PPort := t .cfg .ConsensusCommon .P2pPort .Value .(uint16 )
81- publicIP , err := getPublicIP ()
98+ publicIP , err := t . getPublicIP ()
8299 if err == nil {
83- ecOpen = isPortReachableNATReflection (publicIP , ecP2PPort )
84- ccOpen = isPortReachableNATReflection (publicIP , ccP2PPort )
100+ ecOpen = t . isPortReachableNATReflection (publicIP , ecP2PPort )
101+ ccOpen = t . isPortReachableNATReflection (publicIP , ccP2PPort )
85102 }
103+
86104 if ! ecOpen {
87105 // Fallback to using an external service
88- ecOpen , _ , err = isPortReachableExternalService (ecP2PPort )
106+ ecOpen , _ , err = t . isPortReachableExternalService (ecP2PPort )
89107 if err != nil {
90108 return fmt .Errorf ("error checking port connectivity: %w" , err )
91109 }
@@ -99,14 +117,15 @@ func (t *checkPortConnectivity) run() error {
99117 if t .wasEth1PortOpen {
100118 t .log .Printlnf ("WARNING: Execution client P2P port %d is not accessible from the internet." , ecP2PPort )
101119 }
102- if err := alerting . AlertEth1P2PPortNotOpen (t .cfg , ecP2PPort ); err != nil {
120+ if err := t . alertEth1P2PPortNotOpen (t .cfg , ecP2PPort ); err != nil {
103121 t .log .Printlnf ("WARNING: Could not send Eth1P2PPortNotOpen alert: %s" , err .Error ())
104122 }
105123 }
106124 t .wasEth1PortOpen = ecOpen
125+
107126 if ! ccOpen {
108127 // Fallback to using an external service
109- ccOpen , _ , err = isPortReachableExternalService (ccP2PPort )
128+ ccOpen , _ , err = t . isPortReachableExternalService (ccP2PPort )
110129 if err != nil {
111130 return fmt .Errorf ("error checking port connectivity: %w" , err )
112131 }
@@ -120,7 +139,7 @@ func (t *checkPortConnectivity) run() error {
120139 if t .wasBeaconP2POpen {
121140 t .log .Printlnf ("WARNING: Consensus client P2P port %d is not accessible from the internet." , ccP2PPort )
122141 }
123- if err := alerting . AlertBeaconP2PPortNotOpen (t .cfg , ccP2PPort ); err != nil {
142+ if err := t . alertBeaconP2PPortNotOpen (t .cfg , ccP2PPort ); err != nil {
124143 t .log .Printlnf ("WARNING: Could not send BeaconP2PPortNotOpen alert: %s" , err .Error ())
125144 }
126145 }
0 commit comments