You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.2 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package p2p
  2. import (
  3. "fmt"
  4. "strings"
  5. crypto "github.com/tendermint/go-crypto"
  6. )
  7. const (
  8. maxNodeInfoSize = 10240 // 10Kb
  9. maxNumChannels = 16 // plenty of room for upgrades, for now
  10. )
  11. func MaxNodeInfoSize() int {
  12. return maxNodeInfoSize
  13. }
  14. // NodeInfo is the basic node information exchanged
  15. // between two peers during the Tendermint P2P handshake.
  16. type NodeInfo struct {
  17. // Authenticate
  18. PubKey crypto.PubKey `json:"pub_key"` // authenticated pubkey
  19. ListenAddr string `json:"listen_addr"` // accepting incoming
  20. // Check compatibility
  21. Network string `json:"network"` // network/chain ID
  22. Version string `json:"version"` // major.minor.revision
  23. Channels []byte `json:"channels"` // channels this node knows about
  24. // Sanitize
  25. Moniker string `json:"moniker"` // arbitrary moniker
  26. Other []string `json:"other"` // other application specific data
  27. }
  28. // Validate checks the self-reported NodeInfo is safe.
  29. // It returns an error if the info.PubKey doesn't match the given pubKey,
  30. // or if there are too many Channels or any duplicate Channels.
  31. // TODO: constraints for Moniker/Other? Or is that for the UI ?
  32. func (info NodeInfo) Validate(pubKey crypto.PubKey) error {
  33. if !info.PubKey.Equals(pubKey) {
  34. return fmt.Errorf("info.PubKey (%v) doesn't match peer.PubKey (%v)",
  35. info.PubKey, pubKey)
  36. }
  37. if len(info.Channels) > maxNumChannels {
  38. return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels)
  39. }
  40. channels := make(map[byte]struct{})
  41. for _, ch := range info.Channels {
  42. _, ok := channels[ch]
  43. if ok {
  44. return fmt.Errorf("info.Channels contains duplicate channel id %v", ch)
  45. }
  46. channels[ch] = struct{}{}
  47. }
  48. return nil
  49. }
  50. // CompatibleWith checks if two NodeInfo are compatible with eachother.
  51. // CONTRACT: two nodes are compatible if the major/minor versions match and network match
  52. // and they have at least one channel in common.
  53. func (info NodeInfo) CompatibleWith(other NodeInfo) error {
  54. iMajor, iMinor, _, iErr := splitVersion(info.Version)
  55. oMajor, oMinor, _, oErr := splitVersion(other.Version)
  56. // if our own version number is not formatted right, we messed up
  57. if iErr != nil {
  58. return iErr
  59. }
  60. // version number must be formatted correctly ("x.x.x")
  61. if oErr != nil {
  62. return oErr
  63. }
  64. // major version must match
  65. if iMajor != oMajor {
  66. return fmt.Errorf("Peer is on a different major version. Got %v, expected %v", oMajor, iMajor)
  67. }
  68. // minor version must match
  69. if iMinor != oMinor {
  70. return fmt.Errorf("Peer is on a different minor version. Got %v, expected %v", oMinor, iMinor)
  71. }
  72. // nodes must be on the same network
  73. if info.Network != other.Network {
  74. return fmt.Errorf("Peer is on a different network. Got %v, expected %v", other.Network, info.Network)
  75. }
  76. // if we have no channels, we're just testing
  77. if len(info.Channels) == 0 {
  78. return nil
  79. }
  80. // for each of our channels, check if they have it
  81. found := false
  82. OUTER_LOOP:
  83. for _, ch1 := range info.Channels {
  84. for _, ch2 := range other.Channels {
  85. if ch1 == ch2 {
  86. found = true
  87. break OUTER_LOOP // only need one
  88. }
  89. }
  90. }
  91. if !found {
  92. return fmt.Errorf("Peer has no common channels. Our channels: %v ; Peer channels: %v", info.Channels, other.Channels)
  93. }
  94. return nil
  95. }
  96. func (info NodeInfo) ID() ID {
  97. return PubKeyToID(info.PubKey)
  98. }
  99. // NetAddress returns a NetAddress derived from the NodeInfo -
  100. // it includes the authenticated peer ID and the self-reported
  101. // ListenAddr. Note that the ListenAddr is not authenticated and
  102. // may not match that address actually dialed if its an outbound peer.
  103. func (info NodeInfo) NetAddress() *NetAddress {
  104. id := PubKeyToID(info.PubKey)
  105. addr := info.ListenAddr
  106. netAddr, err := NewNetAddressString(IDAddressString(id, addr))
  107. if err != nil {
  108. panic(err) // everything should be well formed by now
  109. }
  110. return netAddr
  111. }
  112. func (info NodeInfo) String() string {
  113. return fmt.Sprintf("NodeInfo{pk: %v, moniker: %v, network: %v [listen %v], version: %v (%v)}", info.PubKey, info.Moniker, info.Network, info.ListenAddr, info.Version, info.Other)
  114. }
  115. func splitVersion(version string) (string, string, string, error) {
  116. spl := strings.Split(version, ".")
  117. if len(spl) != 3 {
  118. return "", "", "", fmt.Errorf("Invalid version format %v", version)
  119. }
  120. return spl[0], spl[1], spl[2], nil
  121. }