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.

388 lines
11 KiB

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