diff --git a/examples/js_client/hp-client-lib.js b/examples/js_client/hp-client-lib.js index 20ed88d0..b60dc5a9 100644 --- a/examples/js_client/hp-client-lib.js +++ b/examples/js_client/hp-client-lib.js @@ -493,6 +493,12 @@ }) statResponseResolvers = []; } + else if (m.type == "unl_change") { + // UNL change announcement message is handled in this block. + console.log("Received :", m.type); + console.log(m.unl); + } + else { console.log("Received unrecognized contract message: type:" + m.type); return false; diff --git a/src/msg/bson/usrmsg_bson.cpp b/src/msg/bson/usrmsg_bson.cpp index 52fdfb69..f6f10a3c 100644 --- a/src/msg/bson/usrmsg_bson.cpp +++ b/src/msg/bson/usrmsg_bson.cpp @@ -133,6 +133,31 @@ namespace msg::usrmsg::bson encoder.flush(); } + /** + * Constructs unl list container message. + * @param msg String reference to copy the generated bson message string into. + * Message format: + * { + * "type": "unl_change", + * "unl": ["{[1byte(11101101) prefix][32byte]}", ...], // Binary pubkey list of unl nodes. + * } + * @param unl_list The unl node pubkey list to be put in the message. + */ + void create_unl_list_container(std::vector &msg, const ::std::set &unl_list) + { + jsoncons::bson::bson_bytes_encoder encoder(msg); + encoder.begin_object(); + encoder.key(msg::usrmsg::FLD_TYPE); + encoder.string_value(msg::usrmsg::MSGTYPE_UNL_CHANGE); + encoder.key(msg::usrmsg::FLD_UNL); + encoder.begin_array(); + for (std::string_view unl : unl_list) + encoder.byte_string_value(unl); + encoder.end_array(); + encoder.end_object(); + encoder.flush(); + } + /** * Parses a bson message sent by a user. * @param d BSON document to which the parsed bson should be loaded. diff --git a/src/msg/bson/usrmsg_bson.hpp b/src/msg/bson/usrmsg_bson.hpp index de0971be..d3bfd3e6 100644 --- a/src/msg/bson/usrmsg_bson.hpp +++ b/src/msg/bson/usrmsg_bson.hpp @@ -18,6 +18,8 @@ namespace msg::usrmsg::bson const util::merkle_hash_node &hash_root, const std::vector> &unl_sig, const uint64_t lcl_seq_no, std::string_view lcl); + void create_unl_list_container(std::vector &msg, const ::std::set &unl_list); + int verify_user_handshake_response(std::string &extracted_pubkeyhex, std::string &extracted_protocol, std::string_view response, std::string_view original_challenge); diff --git a/src/msg/json/usrmsg_json.cpp b/src/msg/json/usrmsg_json.cpp index e2b364ee..9411b523 100644 --- a/src/msg/json/usrmsg_json.cpp +++ b/src/msg/json/usrmsg_json.cpp @@ -15,6 +15,7 @@ namespace msg::usrmsg::json constexpr const char *SEP_COLON = "\":\""; constexpr const char *SEP_COMMA_NOQUOTE = ",\""; constexpr const char *SEP_COLON_NOQUOTE = "\":"; + constexpr const char *DOUBLE_QUOTE = "\""; // std::vector overload to concatonate string. std::vector &operator+=(std::vector &vec, std::string_view sv) @@ -312,6 +313,41 @@ namespace msg::usrmsg::json msg += "]}"; } + /** + * Constructs unl list container message. + * @param msg String reference to copy the generated json message string into. + * Message format: + * { + * "type": "unl_change", + * ["{[ed prefix][64 characters]}", ...], // Hex pubkey list of unl nodes. + * } + * @param unl_list The unl node pubkey list to be put in the message. + */ + void create_unl_list_container(std::vector &msg, const ::std::set &unl_list) + { + msg.reserve((69 * unl_list.size()) + 30); + msg += "{\""; + msg += msg::usrmsg::FLD_TYPE; + msg += SEP_COLON; + msg += msg::usrmsg::MSGTYPE_UNL_CHANGE; + msg += SEP_COMMA; + msg += msg::usrmsg::FLD_UNL; + msg += "\":["; + + int i = 0; + for (std::string_view unl : unl_list) + { + msg += DOUBLE_QUOTE; + msg += util::to_hex(unl); + msg += DOUBLE_QUOTE; + if (i < unl_list.size() - 1) + msg += ","; + i++; + } + + msg += "]}"; + } + /** * Verifies the user handshake response with the original challenge issued to the user * and the user public key contained in the response. diff --git a/src/msg/json/usrmsg_json.hpp b/src/msg/json/usrmsg_json.hpp index fbdcc145..af34369d 100644 --- a/src/msg/json/usrmsg_json.hpp +++ b/src/msg/json/usrmsg_json.hpp @@ -22,6 +22,8 @@ namespace msg::usrmsg::json const util::merkle_hash_node &hash_root, const std::vector> &unl_sig, const uint64_t lcl_seq_no, std::string_view lcl); + void create_unl_list_container(std::vector &msg, const ::std::set &unl_list); + int verify_user_challenge(std::string &extracted_pubkeyhex, std::string &extracted_protocol, std::string &extracted_server_challenge, std::string_view response, std::string_view original_challenge); diff --git a/src/msg/usrmsg_common.hpp b/src/msg/usrmsg_common.hpp index 6fb4fe2c..21ce2dbc 100644 --- a/src/msg/usrmsg_common.hpp +++ b/src/msg/usrmsg_common.hpp @@ -45,6 +45,7 @@ namespace msg::usrmsg constexpr const char *MSGTYPE_CONTRACT_OUTPUT = "contract_output"; constexpr const char *MSGTYPE_STAT = "stat"; constexpr const char *MSGTYPE_STAT_RESPONSE = "stat_response"; + constexpr const char *MSGTYPE_UNL_CHANGE = "unl_change"; constexpr const char *MSGTYPE_UNKNOWN = "unknown"; // Values diff --git a/src/msg/usrmsg_parser.cpp b/src/msg/usrmsg_parser.cpp index af569e06..d6a42cd8 100644 --- a/src/msg/usrmsg_parser.cpp +++ b/src/msg/usrmsg_parser.cpp @@ -48,6 +48,14 @@ namespace msg::usrmsg busrmsg::create_contract_output_container(msg, outputs, hash_root, unl_sig, lcl_seq_no, lcl); } + void usrmsg_parser::create_unl_list_container(std::vector &msg, const ::std::set &unl_list) const + { + if (protocol == util::PROTOCOL::JSON) + jusrmsg::create_unl_list_container(msg, unl_list); + else + busrmsg::create_unl_list_container(msg, unl_list); + } + int usrmsg_parser::parse(std::string_view message) { if (protocol == util::PROTOCOL::JSON) diff --git a/src/msg/usrmsg_parser.hpp b/src/msg/usrmsg_parser.hpp index f3003aeb..0220b194 100644 --- a/src/msg/usrmsg_parser.hpp +++ b/src/msg/usrmsg_parser.hpp @@ -30,6 +30,8 @@ namespace msg::usrmsg const util::merkle_hash_node &hash_root, const std::vector> &unl_sig, const uint64_t lcl_seq_no, std::string_view lcl) const; + void create_unl_list_container(std::vector &msg, const ::std::set &unl_list) const; + int parse(std::string_view message); int extract_type(std::string &extracted_type) const; diff --git a/src/unl.cpp b/src/unl.cpp index d8b92710..d09e0543 100644 --- a/src/unl.cpp +++ b/src/unl.cpp @@ -111,8 +111,12 @@ namespace unl } // Update the is_unl flag of peer sessions. + // Broadcast changed unl list to all the connected users. if (is_unl_list_changed) + { p2p::update_unl_connections(); + usr::announce_unl_list(list); + } } } // namespace unl diff --git a/src/unl.hpp b/src/unl.hpp index 03a3e88f..5fe12f92 100644 --- a/src/unl.hpp +++ b/src/unl.hpp @@ -3,6 +3,7 @@ #include "pchheader.hpp" #include "p2p/p2p.hpp" +#include "usr/usr.hpp" /** * Manages the UNL public keys of this node. diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 47205454..b97da187 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -417,4 +417,24 @@ namespace usr } } + /** + * Send unl list to all the connected users. + * @param unl_list Set of unl pubkeys. + */ + void announce_unl_list(const std::set &unl_list) + { + std::scoped_lock lock(ctx.users_mutex); + + for (const auto &user : ctx.users) + { + const usr::connected_user &connected_user = user.second; + msg::usrmsg::usrmsg_parser parser(connected_user.protocol); + + std::vector msg; + parser.create_unl_list_container(msg, unl_list); + + connected_user.session.send(msg); + } + } + } // namespace usr \ No newline at end of file diff --git a/src/usr/usr.hpp b/src/usr/usr.hpp index 4abf5325..f465cf27 100644 --- a/src/usr/usr.hpp +++ b/src/usr/usr.hpp @@ -85,6 +85,8 @@ namespace usr bool verify_appbill_check(std::string_view pubkey, const size_t input_len); + void announce_unl_list(const std::set &unl_list); + } // namespace usr #endif \ No newline at end of file