/test/peer_SUITE.erl

https://github.com/helium/erlang-libp2p · Erlang · 181 lines · 135 code · 37 blank · 9 comment · 7 complexity · 1151004d1497e1f9ae52bcb5cd35e961 MD5 · raw file

  1. -module(peer_SUITE).
  2. -include_lib("common_test/include/ct.hrl").
  3. -include_lib("eunit/include/eunit.hrl").
  4. -export([all/0]).
  5. -export([coding_test/1, metadata_test/1, blacklist_test/1, association_test/1, signed_metadata_test/1]).
  6. all() ->
  7. [coding_test,
  8. metadata_test,
  9. blacklist_test,
  10. association_test,
  11. signed_metadata_test
  12. ].
  13. coding_test(_) ->
  14. #{public := PubKey1, secret := PrivKey1} = libp2p_crypto:generate_keys(ecc_compact),
  15. #{public := PubKey2, secret := PrivKey2} = libp2p_crypto:generate_keys(ecc_compact),
  16. SigFun1 = libp2p_crypto:mk_sig_fun(PrivKey1),
  17. SigFun2 = libp2p_crypto:mk_sig_fun(PrivKey2),
  18. #{public := AssocPubKey1, secret := AssocPrivKey1} = libp2p_crypto:generate_keys(ecc_compact),
  19. AssocSigFun1 = libp2p_crypto:mk_sig_fun(AssocPrivKey1),
  20. Associations = [libp2p_peer:mk_association(libp2p_crypto:pubkey_to_bin(AssocPubKey1),
  21. libp2p_crypto:pubkey_to_bin(PubKey1),
  22. AssocSigFun1)
  23. ],
  24. Peer1Map = #{pubkey => libp2p_crypto:pubkey_to_bin(PubKey1),
  25. listen_addrs => ["/ip4/8.8.8.8/tcp/1234"],
  26. connected => [libp2p_crypto:pubkey_to_bin(PubKey2)],
  27. nat_type => static,
  28. associations => [{"wallet", Associations}]
  29. },
  30. {ok, Peer1} = libp2p_peer:from_map(Peer1Map, SigFun1),
  31. DecodedPeer = libp2p_peer:decode(libp2p_peer:encode(Peer1)),
  32. ?assert(libp2p_peer:pubkey_bin(Peer1) == libp2p_peer:pubkey_bin(DecodedPeer)),
  33. ?assert(libp2p_peer:timestamp(Peer1) == libp2p_peer:timestamp(DecodedPeer)),
  34. ?assert(libp2p_peer:listen_addrs(Peer1) == libp2p_peer:listen_addrs(DecodedPeer)),
  35. ?assert(libp2p_peer:nat_type(Peer1) == libp2p_peer:nat_type(DecodedPeer)),
  36. ?assert(libp2p_peer:connected_peers(Peer1) == libp2p_peer:connected_peers(DecodedPeer)),
  37. ?assert(libp2p_peer:metadata(Peer1) == libp2p_peer:metadata(DecodedPeer)),
  38. ?assert(libp2p_peer:association_pubkey_bins(Peer1) == libp2p_peer:association_pubkey_bins(DecodedPeer)),
  39. ?assert(libp2p_peer:is_similar(Peer1, DecodedPeer)),
  40. {ok, InvalidPeer} = libp2p_peer:from_map(Peer1Map, SigFun2),
  41. ?assertError(invalid_signature, libp2p_peer:decode(libp2p_peer:encode(InvalidPeer))),
  42. % Check peer list coding
  43. {ok, Peer2} = libp2p_peer:from_map(#{pubkey => libp2p_crypto:pubkey_to_bin(PubKey2),
  44. listen_addrs => ["/ip4/8.8.8.8/tcp/5678"],
  45. connected => [libp2p_crypto:pubkey_to_bin(PubKey1)],
  46. nat_type => static},
  47. SigFun2),
  48. ?assert(not libp2p_peer:is_similar(Peer1, Peer2)),
  49. ?assertEqual([Peer1, Peer2], libp2p_peer:decode_list(libp2p_peer:encode_list([Peer1, Peer2]))),
  50. ok.
  51. metadata_test(_) ->
  52. #{secret := PrivKey1, public := PubKey1} = libp2p_crypto:generate_keys(ecc_compact),
  53. SigFun1 = libp2p_crypto:mk_sig_fun(PrivKey1),
  54. PeerMap = #{pubkey => libp2p_crypto:pubkey_to_bin(PubKey1),
  55. listen_addrs => ["/ip4/8.8.8.8/tcp/1234"],
  56. connected => [],
  57. nat_type => static},
  58. {ok, Peer} = libp2p_peer:from_map(PeerMap, SigFun1),
  59. Excludes = ["/ip4/8.8.8.8/tcp/1234"],
  60. MPeer = libp2p_peer:metadata_put(Peer, "exclude", term_to_binary(Excludes)),
  61. ?assertEqual(Excludes, binary_to_term(libp2p_peer:metadata_get(MPeer, "exclude", <<>>))),
  62. %% metadata does not affect similarity. Changing this behavior will
  63. %% BREAK peer gossiping so be very careful.
  64. ?assert(libp2p_peer:is_similar(MPeer, Peer)),
  65. %% Transmit metadata as part of peer encode/decode
  66. DecodedPeer = libp2p_peer:decode(libp2p_peer:encode(MPeer)),
  67. ?assertEqual(libp2p_peer:metadata(MPeer), libp2p_peer:metadata(DecodedPeer)),
  68. %% But metadata is NOT transmitted as part of an encoded list of
  69. %% peers. This avoids metedata being gossipped around. It's
  70. %% untrusted, and mostly only locally relevant
  71. ?assertEqual([Peer], libp2p_peer:decode_list(libp2p_peer:encode_list([MPeer]))),
  72. ok.
  73. blacklist_test(_) ->
  74. #{secret := PrivKey1, public := PubKey1} = libp2p_crypto:generate_keys(ecc_compact),
  75. SigFun1 = libp2p_crypto:mk_sig_fun(PrivKey1),
  76. BadListenAddr = "/ip4/8.8.8.8/tcp/1234",
  77. GoodListenAddr = "/ip4/1.1.1.1/tcp/4321",
  78. PeerMap = #{pubkey => libp2p_crypto:pubkey_to_bin(PubKey1),
  79. listen_addrs => [BadListenAddr, GoodListenAddr],
  80. connected => [],
  81. nat_type => static},
  82. {ok, Peer} = libp2p_peer:from_map(PeerMap, SigFun1),
  83. MPeer = libp2p_peer:blacklist_add(Peer, BadListenAddr),
  84. ?assertEqual([BadListenAddr], libp2p_peer:blacklist(MPeer)),
  85. ?assert(libp2p_peer:is_blacklisted(MPeer, BadListenAddr)),
  86. ?assertEqual([GoodListenAddr], libp2p_peer:cleared_listen_addrs(MPeer)),
  87. ok.
  88. association_test(_) ->
  89. #{secret := PrivKey1, public := PubKey1} = libp2p_crypto:generate_keys(ecc_compact),
  90. SigFun1 = libp2p_crypto:mk_sig_fun(PrivKey1),
  91. PeerMap = #{pubkey => libp2p_crypto:pubkey_to_bin(PubKey1),
  92. listen_addrs => ["/ip4/8.8.8.8/tcp/1234"],
  93. connected => [],
  94. nat_type => static},
  95. #{secret := AssocPrivKey1, public := AssocPubKey1} = libp2p_crypto:generate_keys(ecc_compact),
  96. ValidAssoc = libp2p_peer:mk_association(libp2p_crypto:pubkey_to_bin(AssocPubKey1),
  97. libp2p_crypto:pubkey_to_bin(PubKey1),
  98. libp2p_crypto:mk_sig_fun(AssocPrivKey1)),
  99. {ok, ValidPeer} = libp2p_peer:from_map(PeerMap#{associations => [{"wallet", [ValidAssoc]}]}, SigFun1),
  100. ?assert(libp2p_peer:is_association(ValidPeer, "wallet",
  101. libp2p_crypto:pubkey_to_bin(AssocPubKey1))),
  102. ?assert(not libp2p_peer:is_association(ValidPeer, "wallet",
  103. libp2p_crypto:pubkey_to_bin(PubKey1))),
  104. ?assert(not libp2p_peer:is_association(ValidPeer, "no_such_type",
  105. libp2p_crypto:pubkey_to_bin(PubKey1))),
  106. ?assertEqual([{"wallet", [libp2p_crypto:pubkey_to_bin(AssocPubKey1)]}],
  107. libp2p_peer:association_pubkey_bins(ValidPeer)),
  108. ?assertEqual([ValidAssoc], libp2p_peer:associations_get(ValidPeer, "wallet")),
  109. ?assertEqual([{"wallet", [ValidAssoc]}], libp2p_peer:associations(ValidPeer)),
  110. ?assert(libp2p_peer:verify(ValidPeer)),
  111. EncodedValidAssoc = libp2p_peer:association_encode(ValidAssoc),
  112. ?assertEqual(ValidAssoc, libp2p_peer:association_decode(EncodedValidAssoc,
  113. libp2p_crypto:pubkey_to_bin(PubKey1))),
  114. %% Setting the same association dedupes
  115. {ok, ValidPeer2} = libp2p_peer:associations_put(ValidPeer, "wallet", ValidAssoc, SigFun1),
  116. ?assertEqual([ValidAssoc], libp2p_peer:associations_get(ValidPeer2, "wallet")),
  117. %% Make an association signed with the wrong private key
  118. InvalidAssoc = libp2p_peer:mk_association(libp2p_crypto:pubkey_to_bin(AssocPubKey1),
  119. libp2p_crypto:pubkey_to_bin(PubKey1), SigFun1),
  120. {ok, InvalidPeer} = libp2p_peer:associations_put(ValidPeer, "wallet", InvalidAssoc, SigFun1),
  121. ?assert(libp2p_peer:is_association(InvalidPeer, "wallet",
  122. libp2p_crypto:pubkey_to_bin(AssocPubKey1))),
  123. ?assertEqual([InvalidAssoc], libp2p_peer:associations_get(InvalidPeer, "wallet")),
  124. ?assertError(invalid_association_signature, libp2p_peer:verify(InvalidPeer)),
  125. ok.
  126. signed_metadata_test(_) ->
  127. #{secret := PrivKey1, public := PubKey1} = libp2p_crypto:generate_keys(ecc_compact),
  128. SigFun1 = libp2p_crypto:mk_sig_fun(PrivKey1),
  129. PeerMap = #{pubkey => libp2p_crypto:pubkey_to_bin(PubKey1),
  130. listen_addrs => ["/ip4/8.8.8.8/tcp/1234"],
  131. connected => [],
  132. nat_type => static,
  133. signed_metadata => #{<<"hello">> => <<"world">>, <<"number">> => 1, <<"floaty">> => 0.42}},
  134. {ok, Peer} = libp2p_peer:from_map(PeerMap, SigFun1),
  135. ?assertEqual(<<"world">>, libp2p_peer:signed_metadata_get(Peer, <<"hello">>, <<"dlrow">>)),
  136. ?assertEqual(1, libp2p_peer:signed_metadata_get(Peer, <<"number">>, 1)),
  137. ?assertEqual(0.42, libp2p_peer:signed_metadata_get(Peer, <<"floaty">>, 0.42)),
  138. ?assertEqual(<<"dlrow">>, libp2p_peer:signed_metadata_get(Peer, <<"goodbye">>, <<"dlrow">>)),
  139. DecodedPeer = libp2p_peer:decode(libp2p_peer:encode(Peer)),
  140. ?assertEqual(<<"world">>, libp2p_peer:signed_metadata_get(DecodedPeer, <<"hello">>, <<"dlrow">>)),
  141. ?assertEqual(1, libp2p_peer:signed_metadata_get(DecodedPeer, <<"number">>, 1)),
  142. ?assertEqual(0.42, libp2p_peer:signed_metadata_get(DecodedPeer, <<"floaty">>, 0.42)),
  143. ?assertEqual(<<"dlrow">>, libp2p_peer:signed_metadata_get(DecodedPeer, <<"goodbye">>, <<"dlrow">>)),
  144. ok.