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.

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