diff --git a/chainreg/chainregistry.go b/chainreg/chainregistry.go index 02da26391..c3d428611 100644 --- a/chainreg/chainregistry.go +++ b/chainreg/chainregistry.go @@ -122,6 +122,11 @@ const ( // DefaultBitcoinStaticMinRelayFeeRate is the min relay fee used for // static estimators. DefaultBitcoinStaticMinRelayFeeRate = chainfee.FeePerKwFloor + + // DefaultMinOutboundPeers is the min number of connected + // outbound peers the chain backend should have to maintain a + // healthy connection to the network. + DefaultMinOutboundPeers = 6 ) // PartialChainControl contains all the primary interfaces of the chain control @@ -504,7 +509,21 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { cc.HealthCheck = func() error { _, err := chainConn.RawRequest(cmd, nil) - return err + if err != nil { + return err + } + + // On local test networks we usually don't have multiple + // chain backend peers, so we can skip + // the checkOutboundPeers test. + if cfg.Bitcoin.SimNet || cfg.Bitcoin.RegTest { + return nil + } + + // Make sure the bitcoind chain backend maintains a + // healthy connection to the network by checking the + // number of outbound peers. + return checkOutboundPeers(chainConn) } case "btcd": @@ -613,7 +632,21 @@ func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) { // Use a query for our best block as a health check. cc.HealthCheck = func() error { _, _, err := cc.ChainSource.GetBestBlock() - return err + if err != nil { + return err + } + + // On local test networks we usually don't have multiple + // chain backend peers, so we can skip + // the checkOutboundPeers test. + if cfg.Bitcoin.SimNet || cfg.Bitcoin.RegTest { + return nil + } + + // Make sure the btcd chain backend maintains a + // healthy connection to the network by checking the + // number of outbound peers. + return checkOutboundPeers(chainRPC.Client) } // If we're not in simnet or regtest mode, then we'll attempt @@ -840,3 +873,31 @@ var ( }, } ) + +// checkOutboundPeers checks the number of outbound peers connected to the +// provided RPC client. If the number of outbound peers is below 6, a warning +// is logged. This function is intended to ensure that the chain backend +// maintains a healthy connection to the network. +func checkOutboundPeers(client *rpcclient.Client) error { + peers, err := client.GetPeerInfo() + if err != nil { + return err + } + + var outboundPeers int + for _, peer := range peers { + if !peer.Inbound { + outboundPeers++ + } + } + + if outboundPeers < DefaultMinOutboundPeers { + log.Warnf("The chain backend has an insufficient number "+ + "of connected outbound peers (%d connected, expected "+ + "minimum is %d) which can be a security issue. "+ + "Connect to more trusted nodes manually if necessary.", + outboundPeers, DefaultMinOutboundPeers) + } + + return nil +}