Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(cleanup): Get rid of priority multiaddr, publish all of a node's multiaddresses #641

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions cmd/masa-node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
"os/signal"
"syscall"

"github.com/multiformats/go-multiaddr"

"github.com/masa-finance/masa-oracle/internal/versioning"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -114,13 +112,12 @@
}

// Get the multiaddress and IP address of the node
multiAddr := masaNode.GetMultiAddrs() // Get the multiaddress
ipAddr, err := multiAddr.ValueForProtocol(multiaddr.P_IP4) // Get the IP address
multiAddrs, err := masaNode.GetP2PMultiAddrs()

Check warning on line 115 in cmd/masa-node/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/masa-node/main.go#L115

Added line #L115 was not covered by tests
if err != nil {
logrus.Errorf("[-] Error while getting node IP address from %v: %v", multiAddr, err)
logrus.Errorf("[-] Error while getting node multiaddrs: %v", err)
} else {
config.DisplayWelcomeMessage(multiAddrs, cfg.KeyManager.EthAddress, isStaked, cfg.Validator, cfg.TwitterScraper, cfg.TelegramScraper, cfg.DiscordScraper, cfg.WebScraper, versioning.ApplicationVersion, versioning.ProtocolVersion)

Check warning on line 119 in cmd/masa-node/main.go

View check run for this annotation

Codecov / codecov/patch

cmd/masa-node/main.go#L117-L119

Added lines #L117 - L119 were not covered by tests
}
// Display the welcome message with the multiaddress and IP address
config.DisplayWelcomeMessage(multiAddr.String(), ipAddr, cfg.KeyManager.EthAddress, isStaked, cfg.Validator, cfg.TwitterScraper, cfg.TelegramScraper, cfg.DiscordScraper, cfg.WebScraper, versioning.ApplicationVersion, versioning.ProtocolVersion)

<-ctx.Done()
}
Expand Down
23 changes: 4 additions & 19 deletions node/oracle_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@
)

type OracleNode struct {
Host host.Host
Protocol protocol.ID
// TODO: Rm from here and from NodeData? Should not be necessary
priorityAddrs multiaddr.Multiaddr
Host host.Host
Protocol protocol.ID
multiAddrs []multiaddr.Multiaddr
DHT *dht.IpfsDHT
PeerChan chan myNetwork.PeerEvent
Expand All @@ -48,18 +46,6 @@
Context context.Context
}

// GetMultiAddrs returns the priority multiaddr for this node.
// It first checks if the priority address is already set, and returns it if so.
// If not, it determines the priority address from the available multiaddrs using
// the GetPriorityAddress utility function, sets it, and returns it.
func (node *OracleNode) GetMultiAddrs() multiaddr.Multiaddr {
if node.priorityAddrs == nil {
pAddr := myNetwork.GetPriorityAddress(node.multiAddrs)
node.priorityAddrs = pAddr
}
return node.priorityAddrs
}

// GetP2PMultiAddrs returns the multiaddresses for the host in P2P format.
func (node *OracleNode) GetP2PMultiAddrs() ([]multiaddr.Multiaddr, error) {
addrs := node.Host.Addrs()
Expand Down Expand Up @@ -180,8 +166,7 @@
publicEthAddress = node.Options.KeyManager.EthAddress
}

nodeData := pubsub.NewNodeData(node.priorityAddrs, node.Host.ID(), publicEthAddress, pubsub.ActivityJoined)
nodeData.MultiaddrsString = node.priorityAddrs.String()
nodeData := pubsub.NewNodeData(node.Host.Addrs(), node.Host.ID(), publicEthAddress, pubsub.ActivityJoined)

Check warning on line 169 in node/oracle_node.go

View check run for this annotation

Codecov / codecov/patch

node/oracle_node.go#L169

Added line #L169 was not covered by tests
nodeData.IsStaked = node.Options.IsStaked
nodeData.IsTwitterScraper = node.Options.IsTwitterScraper
nodeData.IsDiscordScraper = node.Options.IsDiscordScraper
Expand All @@ -199,7 +184,7 @@
// goroutines to handle discovered peers, listen to the node tracker, and
// discover peers. If this is a bootnode, it adds itself to the node tracker.
func (node *OracleNode) Start() (err error) {
logrus.Infof("[+] Starting node with ID: %s", node.GetMultiAddrs().String())
logrus.Infof("[+] Starting node with ID: %s", node.Host.ID().String())

Check warning on line 187 in node/oracle_node.go

View check run for this annotation

Codecov / codecov/patch

node/oracle_node.go#L187

Added line #L187 was not covered by tests

node.Host.SetStreamHandler(node.Protocol, node.handleStream)
node.Host.SetStreamHandler(node.protocolWithVersion(node.Options.NodeDataSyncProtocol), node.ReceiveNodeData)
Expand Down
22 changes: 19 additions & 3 deletions pkg/config/welcome.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,30 @@

import (
"fmt"

"github.com/multiformats/go-multiaddr"
"github.com/sirupsen/logrus"
)

func DisplayWelcomeMessage(multiAddr, ipAddr, publicKeyHex string, isStaked bool, isValidator bool, isTwitterScraper bool, isTelegramScraper bool, isDiscordScraper bool, isWebScraper bool, version, protocolVersion string) {
func DisplayWelcomeMessage(multiAddrs []multiaddr.Multiaddr, publicKeyHex string, isStaked bool, isValidator bool, isTwitterScraper bool, isTelegramScraper bool, isDiscordScraper bool, isWebScraper bool, version, protocolVersion string) {

Check warning on line 10 in pkg/config/welcome.go

View check run for this annotation

Codecov / codecov/patch

pkg/config/welcome.go#L10

Added line #L10 was not covered by tests
// ANSI escape code for yellow text
yellow := "\033[33m"
blue := "\033[34m"
reset := "\033[0m"

var maddrs, ips string

for _, ma := range multiAddrs {
ip, err := ma.ValueForProtocol(multiaddr.P_IP4) // Get the IP address
if err != nil {
logrus.Errorf("[-] Error while parsing getting IP address for %v: %v", ma, err)
continue

Check warning on line 22 in pkg/config/welcome.go

View check run for this annotation

Codecov / codecov/patch

pkg/config/welcome.go#L16-L22

Added lines #L16 - L22 were not covered by tests
}

maddrs = fmt.Sprintf("%s %s", maddrs, ma)
ips = fmt.Sprintf("%s %s", ips, ip)

Check warning on line 26 in pkg/config/welcome.go

View check run for this annotation

Codecov / codecov/patch

pkg/config/welcome.go#L25-L26

Added lines #L25 - L26 were not covered by tests
}

fmt.Println("")
borderLine := "#######################################"

Expand All @@ -25,8 +41,8 @@

fmt.Printf(blue+"%-20s %s\n"+reset, "Application Version:", yellow+version)
fmt.Printf(blue+"%-20s %s\n"+reset, "Protocol Version:", yellow+protocolVersion)
fmt.Printf(blue+"%-20s %s\n"+reset, "Multiaddress:", multiAddr)
fmt.Printf(blue+"%-20s %s\n"+reset, "IP Address:", ipAddr)
fmt.Printf(blue+"%-20s %s\n"+reset, "Multiaddresses:", maddrs)
fmt.Printf(blue+"%-20s %s\n"+reset, "IP Addresses:", ips)

Check warning on line 45 in pkg/config/welcome.go

View check run for this annotation

Codecov / codecov/patch

pkg/config/welcome.go#L44-L45

Added lines #L44 - L45 were not covered by tests
fmt.Printf(blue+"%-20s %s\n"+reset, "Public Key:", publicKeyHex)
fmt.Printf(blue+"%-20s %t\n"+reset, "Is Staked:", isStaked)
fmt.Printf(blue+"%-20s %t\n"+reset, "Is Validator:", isValidator)
Expand Down
171 changes: 0 additions & 171 deletions pkg/network/address.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package network

import (
"fmt"
"io"
"net"
"net/http"
"strings"

"github.com/libp2p/go-libp2p/core/host"
Expand All @@ -13,9 +9,6 @@ import (
"github.com/sirupsen/logrus"
)

// The URL of the GCP metadata server for the external IP
const externalIPURL = "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip"

// GetMultiAddressesForHost returns the multiaddresses for the host
func GetMultiAddressesForHost(host host.Host) ([]multiaddr.Multiaddr, error) {
peerInfo := peer.AddrInfo{
Expand All @@ -38,170 +31,6 @@ func GetMultiAddressesForHost(host host.Host) ([]multiaddr.Multiaddr, error) {
return addresses, nil
}

// getPublicMultiAddress returns the best public IP address (for some definition of "best")
// TODO: This is not guaranteed to work, and should not be necessary since we're using AutoNAT
func getPublicMultiAddress(addrs []multiaddr.Multiaddr) multiaddr.Multiaddr {
ipBytes, err := Get("https://api.ipify.org?format=text", nil)
externalIP := net.ParseIP(string(ipBytes))
if err != nil {
logrus.Warnf("[-] Failed to get public IP: %v", err)
return nil
}
if externalIP == nil || externalIP.IsPrivate() {
return nil
}

var addrToCopy multiaddr.Multiaddr
if len(addrs) > 0 {
addrToCopy = addrs[0]
}
publicMultiaddr, err := replaceIPComponent(addrToCopy, externalIP.String())
if err != nil {
logrus.Warnf("[-] Failed to create multiaddr with public IP: %v", err)
return nil
}
return publicMultiaddr
}

// GetPriorityAddress returns the best public or private IP address
// TODO: rm?
func GetPriorityAddress(addrs []multiaddr.Multiaddr) multiaddr.Multiaddr {
var bestPrivateAddr multiaddr.Multiaddr
bestPublicAddr := getPublicMultiAddress(addrs)

for _, addr := range addrs {
ipComponent, err := addr.ValueForProtocol(multiaddr.P_IP4)
if err != nil {
ipComponent, err = addr.ValueForProtocol(multiaddr.P_IP6)
if err != nil {
continue // Not an IP address
}
}
ip := net.ParseIP(ipComponent)
if ip == nil || ip.IsLoopback() {
continue // Skip invalid or loopback addresses
}
if ip.IsPrivate() {
// If it's the first private address found or if it's preferred over the current best, keep it
if bestPrivateAddr == nil || isPreferredAddress(addr) {
bestPrivateAddr = addr
}
} else {
// If it's the first public address found or if it's preferred over the current best, keep it
if bestPublicAddr == nil || isPreferredAddress(addr) {
bestPublicAddr = addr
}
}
}
var baseAddr multiaddr.Multiaddr
// Prefer public addresses over private ones
if bestPublicAddr != nil {
baseAddr = bestPublicAddr
} else if bestPrivateAddr != nil {
baseAddr = bestPrivateAddr
} else {
logrus.Warn("No address matches the priority criteria, returning the first entry")
baseAddr = addrs[0]
}
logrus.Infof("Best public address: %s", bestPublicAddr)
logrus.Debugf("Best private address: %s", bestPrivateAddr)
logrus.Debugf("Base address: %s", baseAddr)
gcpAddr := replaceGCPAddress(baseAddr)
if gcpAddr != nil {
baseAddr = gcpAddr
}
return baseAddr
}

func replaceGCPAddress(addr multiaddr.Multiaddr) multiaddr.Multiaddr {
// After finding the best address, try to get the GCP external IP
var err error
var bestAddr multiaddr.Multiaddr
gotExternalIP, externalIP := getGCPExternalIP()
if gotExternalIP && externalIP != "" {
bestAddr, err = replaceIPComponent(addr, externalIP)
if err != nil {
logrus.Warnf("Failed to replace IP component: %s", err)
return nil
}
}
logrus.Debug("Got external IP: ", gotExternalIP)
logrus.Debug("Address after replacing IP component: ", bestAddr)
return bestAddr
}

func replaceIPComponent(maddr multiaddr.Multiaddr, newIP string) (multiaddr.Multiaddr, error) {
var components []multiaddr.Multiaddr
for _, component := range multiaddr.Split(maddr) {
if component.Protocols()[0].Code == multiaddr.P_IP4 || component.Protocols()[0].Code == multiaddr.P_IP6 {
// Create a new IP component
newIPComponent, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s", newIP))
if err != nil {
return nil, err
}
components = append(components, newIPComponent)
} else {
components = append(components, component)
}
}
return multiaddr.Join(components...), nil
}

func getGCPExternalIP() (bool, string) {

// Create a new HTTP client with a specific timeout
client := &http.Client{}

// Make a request to the metadata server
req, err := http.NewRequest("GET", externalIPURL, nil)
if err != nil {
return false, ""
}

// GCP metadata server requires this specific header
req.Header.Add("Metadata-Flavor", "Google")

// Perform the request
resp, err := client.Do(req)
if err != nil {
return false, ""
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
logrus.Error(err)
}
}(resp.Body)

// Check if the metadata server returns a successful status code
if resp.StatusCode != http.StatusOK {
logrus.Debug("Metadata server response status: ", resp.StatusCode)
return false, ""
}
//Read the external IP from the response
body, err := io.ReadAll(resp.Body)
if err != nil {
return true, ""
}
// Check that the response is a valid IP address
if net.ParseIP(string(body)) == nil {
return false, ""
}
logrus.Debug("External IP from metadata server: ", string(body))
return true, string(body)
}

// isPreferredAddress checks if the multiaddress contains the UDP protocol
func isPreferredAddress(addr multiaddr.Multiaddr) bool {
// Check if the multiaddress contains the UDP protocol
for _, p := range addr.Protocols() {
if p.Code == multiaddr.P_UDP {
return true
}
}
return false
}

// GetBootNodesMultiAddress returns the multiaddresses for the bootstrap nodes
func GetBootNodesMultiAddress(bootstrapNodes []string) ([]multiaddr.Multiaddr, error) {
addrs := make([]multiaddr.Multiaddr, 0)
Expand Down
12 changes: 5 additions & 7 deletions pkg/network/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,11 @@
logrus.Warningf("[-] Failed to connect to peer %s, will retry...", availPeer.ID.String())
continue
} else {
logrus.Infof("[+] Connected to peer %s", availPeer.ID.String())
}
} else {
for _, bn := range bootNodes {
if len(bn) > 0 {
logrus.Info("[-] Not connected to any bootnode. Attempting to reconnect...")
reconnectToBootnodes(ctx, host, bootNodes)
for _, bn := range bootNodes {
if len(bn) > 0 {
logrus.Info("[-] Not connected to any bootnode. Attempting to reconnect...")
reconnectToBootnodes(ctx, host, bootNodes)
}

Check warning on line 124 in pkg/network/discover.go

View check run for this annotation

Codecov / codecov/patch

pkg/network/discover.go#L120-L124

Added lines #L120 - L124 were not covered by tests
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions pkg/network/kdht.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ func EnableDHT(ctx context.Context, host host.Host, bootstrapNodes []multiaddr.M
options = append(options, dht.RoutingTableRefreshPeriod(time.Minute*5)) // Set refresh interval
options = append(options, dht.Mode(dht.ModeAutoServer))
options = append(options, dht.ProtocolPrefix(prefix))
// WTF: Why?
options = append(options, dht.NamespacedValidator("db", dbValidator{}))

kademliaDHT, err := dht.New(ctx, host, options...)
Expand Down Expand Up @@ -87,7 +86,7 @@ func EnableDHT(ctx context.Context, host host.Host, bootstrapNodes []multiaddr.M
} else if !added {
logrus.Warningf("[-] Bootstrap peer %s was not added to DHT", peerInfo.ID)
} else {
logrus.Infof("[+] Successfully added bootstrap peer %s to DHT", peerInfo.ID)
logrus.Infof("[+] Successfully added bootstrap peer %s to DHT: %v", peerInfo.ID, peerInfo)
}

wg.Add(1)
Expand Down
11 changes: 8 additions & 3 deletions pkg/pubsub/node_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,19 @@ type NodeData struct {

// NewNodeData creates a new NodeData struct initialized with the given
// parameters. It is used to represent data about a node in the network.
func NewNodeData(addr multiaddr.Multiaddr, peerId peer.ID, publicKey string, activity int) *NodeData {
func NewNodeData(addrs []multiaddr.Multiaddr, peerId peer.ID, publicKey string, activity int) *NodeData {
multiaddrs := make([]JSONMultiaddr, 0)
multiaddrs = append(multiaddrs, JSONMultiaddr{addr})
var mas string

for _, ma := range addrs {
multiaddrs = append(multiaddrs, JSONMultiaddr{ma})
mas = fmt.Sprintf("%s %s", mas, ma.String())
}

return &NodeData{
PeerId: peerId,
Multiaddrs: multiaddrs,
MultiaddrsString: addr.String(),
MultiaddrsString: mas,
LastUpdatedUnix: time.Now().Unix(),
CurrentUptime: 0,
AccumulatedUptime: 0,
Expand Down
Loading