netmetrics.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package p2p
  2. import (
  3. gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
  4. "github.com/certusone/wormhole/node/pkg/vaa"
  5. "github.com/certusone/wormhole/node/pkg/version"
  6. "github.com/ethereum/go-ethereum/common"
  7. "github.com/libp2p/go-libp2p-core/peer"
  8. "github.com/prometheus/client_golang/prometheus"
  9. "github.com/prometheus/client_golang/prometheus/promauto"
  10. "math"
  11. "regexp"
  12. "strconv"
  13. )
  14. var (
  15. wormholeNetworkNodeHeight = promauto.NewGaugeVec(
  16. prometheus.GaugeOpts{
  17. Name: "wormhole_network_node_height",
  18. Help: "Network height of the given guardian node per network",
  19. }, []string{"guardian_addr", "node_id", "node_name", "network"})
  20. wormholeNetworkNodeErrors = promauto.NewGaugeVec(
  21. prometheus.GaugeOpts{
  22. Name: "wormhole_network_node_errors_count",
  23. Help: "Number of errors the given guardian node encountered per network",
  24. }, []string{"guardian_addr", "node_id", "node_name", "network"})
  25. wormholeNetworkVersion = promauto.NewGaugeVec(
  26. prometheus.GaugeOpts{
  27. Name: "wormhole_network_node_version",
  28. Help: "Network version of the given guardian node per network",
  29. }, []string{"guardian_addr", "node_id", "node_name", "network", "version"})
  30. )
  31. func collectNodeMetrics(addr common.Address, peerId peer.ID, hb *gossipv1.Heartbeat) {
  32. for _, n := range hb.Networks {
  33. if n == nil {
  34. continue
  35. }
  36. chain := vaa.ChainID(n.Id)
  37. wormholeNetworkNodeHeight.WithLabelValues(
  38. addr.Hex(), peerId.Pretty(), hb.NodeName, chain.String()).Set(float64(n.Height))
  39. wormholeNetworkNodeErrors.WithLabelValues(
  40. addr.Hex(), peerId.Pretty(), hb.NodeName, chain.String()).Set(float64(n.ErrorCount))
  41. wormholeNetworkVersion.WithLabelValues(
  42. addr.Hex(), peerId.Pretty(), hb.NodeName, chain.String(),
  43. sanitizeVersion(hb.Version, version.Version())).Set(1)
  44. }
  45. }
  46. var (
  47. // Parse version string using regular expression.
  48. // The version string should be in the format of "vX.Y.Z"
  49. // where X, Y and Z are integers. Suffixes are ignored.
  50. reVersion = regexp.MustCompile(`^v(\d+)\.(\d+)\.(\d+)`)
  51. )
  52. // sanitizeVersion cleans up the version string to prevent an attacker from executing a cardinality attack.
  53. func sanitizeVersion(version string, reference string) string {
  54. // Match groups of reVersion
  55. components := reVersion.FindStringSubmatch(version)
  56. referenceComponents := reVersion.FindStringSubmatch(reference)
  57. // Compare components of the version string with the reference and ensure
  58. // that the distance is less than 5.
  59. for i, c := range components {
  60. if len(referenceComponents) <= i {
  61. return "other"
  62. }
  63. cInt, _ := strconv.Atoi(c)
  64. cRefInt, _ := strconv.Atoi(referenceComponents[i])
  65. if math.Abs(float64(cInt-cRefInt)) > 5 {
  66. return "other"
  67. }
  68. }
  69. v := reVersion.FindString(version)
  70. if v == "" {
  71. return "other"
  72. }
  73. return v
  74. }