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.

379 lines
11 KiB

  1. package p2p_test
  2. import (
  3. "net"
  4. "strings"
  5. "testing"
  6. "github.com/stretchr/testify/require"
  7. "github.com/tendermint/tendermint/crypto/ed25519"
  8. "github.com/tendermint/tendermint/p2p"
  9. )
  10. func TestNewNodeID(t *testing.T) {
  11. // Most tests are in TestNodeID_Validate, this just checks that it's validated.
  12. testcases := []struct {
  13. input string
  14. expect p2p.NodeID
  15. ok bool
  16. }{
  17. {"", "", false},
  18. {"foo", "", false},
  19. {"00112233445566778899aabbccddeeff00112233", "00112233445566778899aabbccddeeff00112233", true},
  20. {"00112233445566778899AABBCCDDEEFF00112233", "00112233445566778899aabbccddeeff00112233", true},
  21. {"00112233445566778899aabbccddeeff0011223", "", false},
  22. {"00112233445566778899aabbccddeeff0011223g", "", false},
  23. }
  24. for _, tc := range testcases {
  25. tc := tc
  26. t.Run(tc.input, func(t *testing.T) {
  27. id, err := p2p.NewNodeID(tc.input)
  28. if !tc.ok {
  29. require.Error(t, err)
  30. } else {
  31. require.NoError(t, err)
  32. require.Equal(t, id, tc.expect)
  33. }
  34. })
  35. }
  36. }
  37. func TestNewNodeIDFromPubKey(t *testing.T) {
  38. privKey := ed25519.GenPrivKeyFromSecret([]byte("foo"))
  39. nodeID := p2p.NodeIDFromPubKey(privKey.PubKey())
  40. require.Equal(t, p2p.NodeID("045f5600654182cfeaccfe6cb19f0642e8a59898"), nodeID)
  41. }
  42. func TestNodeID_Bytes(t *testing.T) {
  43. testcases := []struct {
  44. nodeID p2p.NodeID
  45. expect []byte
  46. ok bool
  47. }{
  48. {"", []byte{}, true},
  49. {"01f0", []byte{0x01, 0xf0}, true},
  50. {"01F0", []byte{0x01, 0xf0}, true},
  51. {"01F", nil, false},
  52. {"01g0", nil, false},
  53. }
  54. for _, tc := range testcases {
  55. tc := tc
  56. t.Run(string(tc.nodeID), func(t *testing.T) {
  57. bz, err := tc.nodeID.Bytes()
  58. if tc.ok {
  59. require.NoError(t, err)
  60. require.Equal(t, tc.expect, bz)
  61. } else {
  62. require.Error(t, err)
  63. }
  64. })
  65. }
  66. }
  67. func TestNodeID_Validate(t *testing.T) {
  68. testcases := []struct {
  69. nodeID p2p.NodeID
  70. ok bool
  71. }{
  72. {"", false},
  73. {"00", false},
  74. {"00112233445566778899aabbccddeeff00112233", true},
  75. {"00112233445566778899aabbccddeeff001122334", false},
  76. {"00112233445566778899aabbccddeeffgg001122", false},
  77. {"00112233445566778899AABBCCDDEEFF00112233", false},
  78. }
  79. for _, tc := range testcases {
  80. tc := tc
  81. t.Run(string(tc.nodeID), func(t *testing.T) {
  82. err := tc.nodeID.Validate()
  83. if tc.ok {
  84. require.NoError(t, err)
  85. } else {
  86. require.Error(t, err)
  87. }
  88. })
  89. }
  90. }
  91. func TestParseNodeAddress(t *testing.T) {
  92. user := "00112233445566778899aabbccddeeff00112233"
  93. id := p2p.NodeID(user)
  94. testcases := []struct {
  95. url string
  96. expect p2p.NodeAddress
  97. ok bool
  98. }{
  99. // Valid addresses.
  100. {
  101. "mconn://" + user + "@127.0.0.1:26657/some/path?foo=bar",
  102. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "127.0.0.1", Port: 26657, Path: "/some/path?foo=bar"},
  103. true,
  104. },
  105. {
  106. "TCP://" + strings.ToUpper(user) + "@hostname.DOMAIN:8080/Path/%f0%9f%91%8B#Anchor",
  107. p2p.NodeAddress{Protocol: "tcp", NodeID: id, Hostname: "hostname.domain", Port: 8080, Path: "/Path/👋#Anchor"},
  108. true,
  109. },
  110. {
  111. user + "@127.0.0.1",
  112. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "127.0.0.1"},
  113. true,
  114. },
  115. {
  116. user + "@hostname.domain",
  117. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "hostname.domain"},
  118. true,
  119. },
  120. {
  121. user + "@hostname.domain:80",
  122. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "hostname.domain", Port: 80},
  123. true,
  124. },
  125. {
  126. user + "@%F0%9F%91%8B",
  127. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "👋"},
  128. true,
  129. },
  130. {
  131. user + "@%F0%9F%91%8B:80/path",
  132. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "👋", Port: 80, Path: "/path"},
  133. true,
  134. },
  135. {
  136. user + "@127.0.0.1:26657",
  137. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "127.0.0.1", Port: 26657},
  138. true,
  139. },
  140. {
  141. user + "@127.0.0.1:26657/path",
  142. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "127.0.0.1", Port: 26657, Path: "/path"},
  143. true,
  144. },
  145. {
  146. user + "@0.0.0.0:0",
  147. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "0.0.0.0", Port: 0},
  148. true,
  149. },
  150. {
  151. "memory:" + user,
  152. p2p.NodeAddress{Protocol: "memory", NodeID: id},
  153. true,
  154. },
  155. {
  156. user + "@[1::]",
  157. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "1::"},
  158. true,
  159. },
  160. {
  161. "mconn://" + user + "@[fd80:b10c::2]:26657",
  162. p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "fd80:b10c::2", Port: 26657},
  163. true,
  164. },
  165. // Invalid addresses.
  166. {"", p2p.NodeAddress{}, false},
  167. {"127.0.0.1", p2p.NodeAddress{}, false},
  168. {"hostname", p2p.NodeAddress{}, false},
  169. {"scheme:", p2p.NodeAddress{}, false},
  170. {"memory:foo", p2p.NodeAddress{}, false},
  171. {user + "@%F%F0", p2p.NodeAddress{}, false},
  172. {"//" + user + "@127.0.0.1", p2p.NodeAddress{}, false},
  173. {"://" + user + "@127.0.0.1", p2p.NodeAddress{}, false},
  174. {"mconn://foo@127.0.0.1", p2p.NodeAddress{}, false},
  175. {"mconn://" + user + "@127.0.0.1:65536", p2p.NodeAddress{}, false},
  176. {"mconn://" + user + "@:80", p2p.NodeAddress{}, false},
  177. }
  178. for _, tc := range testcases {
  179. tc := tc
  180. t.Run(tc.url, func(t *testing.T) {
  181. address, err := p2p.ParseNodeAddress(tc.url)
  182. if !tc.ok {
  183. require.Error(t, err)
  184. } else {
  185. require.NoError(t, err)
  186. require.Equal(t, tc.expect, address)
  187. }
  188. })
  189. }
  190. }
  191. func TestNodeAddress_Resolve(t *testing.T) {
  192. id := p2p.NodeID("00112233445566778899aabbccddeeff00112233")
  193. testcases := []struct {
  194. address p2p.NodeAddress
  195. expect p2p.Endpoint
  196. ok bool
  197. }{
  198. // Valid networked addresses (with hostname).
  199. {
  200. p2p.NodeAddress{Protocol: "tcp", Hostname: "127.0.0.1", Port: 80, Path: "/path"},
  201. p2p.Endpoint{Protocol: "tcp", IP: net.IPv4(127, 0, 0, 1), Port: 80, Path: "/path"},
  202. true,
  203. },
  204. {
  205. p2p.NodeAddress{Protocol: "tcp", Hostname: "localhost", Port: 80, Path: "/path"},
  206. p2p.Endpoint{Protocol: "tcp", IP: net.IPv4(127, 0, 0, 1), Port: 80, Path: "/path"},
  207. true,
  208. },
  209. {
  210. p2p.NodeAddress{Protocol: "tcp", Hostname: "localhost", Port: 80, Path: "/path"},
  211. p2p.Endpoint{Protocol: "tcp", IP: net.IPv6loopback, Port: 80, Path: "/path"},
  212. true,
  213. },
  214. {
  215. p2p.NodeAddress{Protocol: "tcp", Hostname: "127.0.0.1"},
  216. p2p.Endpoint{Protocol: "tcp", IP: net.IPv4(127, 0, 0, 1)},
  217. true,
  218. },
  219. {
  220. p2p.NodeAddress{Protocol: "tcp", Hostname: "::1"},
  221. p2p.Endpoint{Protocol: "tcp", IP: net.IPv6loopback},
  222. true,
  223. },
  224. {
  225. p2p.NodeAddress{Protocol: "tcp", Hostname: "8.8.8.8"},
  226. p2p.Endpoint{Protocol: "tcp", IP: net.IPv4(8, 8, 8, 8)},
  227. true,
  228. },
  229. {
  230. p2p.NodeAddress{Protocol: "tcp", Hostname: "2001:0db8::ff00:0042:8329"},
  231. p2p.Endpoint{Protocol: "tcp", IP: []byte{
  232. 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x42, 0x83, 0x29}},
  233. true,
  234. },
  235. {
  236. p2p.NodeAddress{Protocol: "tcp", Hostname: "some.missing.host.tendermint.com"},
  237. p2p.Endpoint{},
  238. false,
  239. },
  240. // Valid non-networked addresses.
  241. {
  242. p2p.NodeAddress{Protocol: "memory", NodeID: id},
  243. p2p.Endpoint{Protocol: "memory", Path: string(id)},
  244. true,
  245. },
  246. {
  247. p2p.NodeAddress{Protocol: "memory", NodeID: id, Path: string(id)},
  248. p2p.Endpoint{Protocol: "memory", Path: string(id)},
  249. true,
  250. },
  251. // Invalid addresses.
  252. {p2p.NodeAddress{}, p2p.Endpoint{}, false},
  253. {p2p.NodeAddress{Hostname: "127.0.0.1"}, p2p.Endpoint{}, false},
  254. {p2p.NodeAddress{Protocol: "tcp", Hostname: "127.0.0.1:80"}, p2p.Endpoint{}, false},
  255. {p2p.NodeAddress{Protocol: "memory"}, p2p.Endpoint{}, false},
  256. {p2p.NodeAddress{Protocol: "memory", Path: string(id)}, p2p.Endpoint{}, false},
  257. {p2p.NodeAddress{Protocol: "tcp", Hostname: "💥"}, p2p.Endpoint{}, false},
  258. }
  259. for _, tc := range testcases {
  260. tc := tc
  261. t.Run(tc.address.String(), func(t *testing.T) {
  262. endpoints, err := tc.address.Resolve(ctx)
  263. if !tc.ok {
  264. require.Error(t, err)
  265. return
  266. }
  267. require.Contains(t, endpoints, tc.expect)
  268. })
  269. }
  270. }
  271. func TestNodeAddress_String(t *testing.T) {
  272. id := p2p.NodeID("00112233445566778899aabbccddeeff00112233")
  273. user := string(id)
  274. testcases := []struct {
  275. address p2p.NodeAddress
  276. expect string
  277. }{
  278. // Valid networked addresses (with hostname).
  279. {
  280. p2p.NodeAddress{Protocol: "tcp", NodeID: id, Hostname: "host", Port: 80, Path: "/path/sub?foo=bar&x=y#anchor"},
  281. "tcp://" + user + "@host:80/path/sub%3Ffoo=bar&x=y%23anchor",
  282. },
  283. {
  284. p2p.NodeAddress{Protocol: "tcp", NodeID: id, Hostname: "host.domain"},
  285. "tcp://" + user + "@host.domain",
  286. },
  287. {
  288. p2p.NodeAddress{NodeID: id, Hostname: "host", Port: 80, Path: "foo/bar"},
  289. user + "@host:80/foo/bar",
  290. },
  291. // Valid non-networked addresses (without hostname).
  292. {
  293. p2p.NodeAddress{Protocol: "memory", NodeID: id, Path: string(id)},
  294. "memory:" + user,
  295. },
  296. {
  297. p2p.NodeAddress{Protocol: "memory", NodeID: id},
  298. "memory:" + user,
  299. },
  300. // Addresses with weird contents, which are technically fine (not harmful).
  301. {
  302. p2p.NodeAddress{Protocol: "💬", NodeID: "👨", Hostname: "💻", Port: 80, Path: "🛣"},
  303. "💬://%F0%9F%91%A8@%F0%9F%92%BB:80/%F0%9F%9B%A3",
  304. },
  305. // Partial (invalid) addresses.
  306. {p2p.NodeAddress{}, ""},
  307. {p2p.NodeAddress{NodeID: id}, user + "@"},
  308. {p2p.NodeAddress{Protocol: "tcp"}, "tcp:"},
  309. {p2p.NodeAddress{Hostname: "host"}, "host"},
  310. {p2p.NodeAddress{Port: 80}, ""},
  311. {p2p.NodeAddress{Path: "path"}, "/path"},
  312. {p2p.NodeAddress{NodeID: id, Port: 80}, user + "@"},
  313. {p2p.NodeAddress{Protocol: "tcp", Hostname: "host"}, "tcp://host"},
  314. {
  315. p2p.NodeAddress{Protocol: "memory", NodeID: id, Path: "path"},
  316. "memory://00112233445566778899aabbccddeeff00112233@/path",
  317. },
  318. {
  319. p2p.NodeAddress{Protocol: "memory", NodeID: id, Port: 80},
  320. "memory:00112233445566778899aabbccddeeff00112233",
  321. },
  322. }
  323. for _, tc := range testcases {
  324. tc := tc
  325. t.Run(tc.address.String(), func(t *testing.T) {
  326. require.Equal(t, tc.expect, tc.address.String())
  327. })
  328. }
  329. }
  330. func TestNodeAddress_Validate(t *testing.T) {
  331. id := p2p.NodeID("00112233445566778899aabbccddeeff00112233")
  332. testcases := []struct {
  333. address p2p.NodeAddress
  334. ok bool
  335. }{
  336. // Valid addresses.
  337. {p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "host", Port: 80, Path: "/path"}, true},
  338. {p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "host"}, true},
  339. {p2p.NodeAddress{Protocol: "mconn", NodeID: id, Path: "path"}, true},
  340. {p2p.NodeAddress{Protocol: "mconn", NodeID: id, Hostname: "👋", Path: "👋"}, true},
  341. // Invalid addresses.
  342. {p2p.NodeAddress{}, false},
  343. {p2p.NodeAddress{NodeID: "foo", Hostname: "host"}, false},
  344. {p2p.NodeAddress{Protocol: "mconn", NodeID: id}, true},
  345. {p2p.NodeAddress{Protocol: "mconn", NodeID: "foo", Hostname: "host"}, false},
  346. {p2p.NodeAddress{Protocol: "mconn", NodeID: id, Port: 80, Path: "path"}, false},
  347. }
  348. for _, tc := range testcases {
  349. tc := tc
  350. t.Run(tc.address.String(), func(t *testing.T) {
  351. err := tc.address.Validate()
  352. if tc.ok {
  353. require.NoError(t, err)
  354. } else {
  355. require.Error(t, err)
  356. }
  357. })
  358. }
  359. }