diff --git a/CMakeLists.txt b/CMakeLists.txt index 3422e15a..c782fd3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,8 +12,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") -#-------hpcore------- - +# -------hpcore------- add_subdirectory(src/killswitch) add_executable(hpcore @@ -76,6 +75,7 @@ target_link_libraries(hpcore ) add_custom_command(TARGET hpcore POST_BUILD + # COMMAND strip ./build/hpcore COMMAND cp ./test/bin/hpws ./test/bin/hpfs ./build/ ) @@ -85,10 +85,10 @@ target_precompile_headers(hpcore PUBLIC src/pchheader.hpp) # Create docker image for local cluster testing from hpcore build output with 'make docker' # Requires docker to be runnable without 'sudo' add_custom_target(docker - COMMAND mkdir -p ./test/local-cluster/bin - COMMAND cp ./build/hpcore ./test/local-cluster/bin/ - COMMAND cp ./test/bin/libblake3.so ./test/bin/hpws ./test/bin/hpfs ./test/local-cluster/bin/ - COMMAND docker build -t hpcore:latest -t hpcore:0.6.1 -f ./test/local-cluster/Dockerfile ./test/local-cluster/bin/ + COMMAND mkdir -p ./test/local-cluster/bin + COMMAND cp ./build/hpcore ./test/local-cluster/bin/ + COMMAND cp ./test/bin/libblake3.so ./test/bin/hpws ./test/bin/hpfs ./test/local-cluster/bin/ + COMMAND docker build -t hpcore:latest -t hpcore:0.6.3 -f ./test/local-cluster/Dockerfile ./test/local-cluster/bin/ ) set_target_properties(docker PROPERTIES EXCLUDE_FROM_ALL TRUE) add_dependencies(docker hpcore) diff --git a/src/consensus.cpp b/src/consensus.cpp index 4b18ef78..d67f6780 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -12,6 +12,7 @@ #include "util/h32.hpp" #include "util/sequence_hash.hpp" #include "unl.hpp" +#include "ledger/ledger_common.hpp" #include "ledger/ledger.hpp" #include "ledger/ledger_query.hpp" #include "consensus.hpp" @@ -24,7 +25,6 @@ namespace p2pmsg = msg::fbuf::p2pmsg; namespace consensus { constexpr float STAGE_THRESHOLD_RATIO[3] = {0.5, 0.65, 0.8}; - constexpr size_t ROUND_NONCE_SIZE = 64; constexpr const char *HPFS_SESSION_NAME = "ro_patch_file_to_hp"; // Max no. of time to get unreliable votes before we try heuristics to increase vote receiving reliability. @@ -242,11 +242,8 @@ namespace consensus */ void attempt_ledger_close() { - std::map hash_votes; // Votes on the proposal hash. - std::map cp_root_hash; // Stores one of proposal to match its root hash. - util::h32 majority_hash = util::h32_empty; - - uint32_t stage3_prop_count = 0; // Keep track of the number of stage 3 proposals received. + std::map> proposal_groups; // Stores sets of proposals against grouped by their root hashes. + uint32_t stage3_prop_count = 0; // Keep track of the number of stage 3 proposals received. // Count votes of all stage 3 proposal hashes. for (const auto &[pubkey, cp] : ctx.candidate_proposals) @@ -254,11 +251,10 @@ namespace consensus if (cp.stage == 3) { stage3_prop_count++; - increment(hash_votes, cp.root_hash); - if (!cp_root_hash.count(cp.root_hash)) - cp_root_hash.try_emplace(cp.root_hash, cp); + proposal_groups[cp.root_hash].push_back(cp); } } + // Threshold is devided by 100 to convert average to decimal. const uint32_t min_votes_required = ceil((conf::cfg.contract.consensus.threshold * unl::count()) / 100.0); if (stage3_prop_count < min_votes_required) @@ -270,12 +266,13 @@ namespace consensus // Find the winning hash and no. of votes for it. uint32_t winning_votes = 0; - for (const auto [hash, votes] : hash_votes) + util::h32 winning_hash = util::h32_empty; + for (const auto [hash, proposals] : proposal_groups) { - if (votes > winning_votes) + if (proposals.size() > winning_votes) { - winning_votes = votes; - majority_hash = hash; + winning_votes = proposals.size(); + winning_hash = hash; } } @@ -285,20 +282,16 @@ namespace consensus return; } - const auto itr = cp_root_hash.find(majority_hash); - if (itr == cp_root_hash.end()) - { - LOG_ERROR << "No proposal matching the majority hash found."; - return; - } - const p2p::proposal &majority_prop = itr->second; + // Consensus reached. This is the winning set of proposals. + std::vector &winning_group = proposal_groups[winning_hash]; - LOG_DEBUG << "Closing ledger with proposal:" << majority_prop.root_hash; + p2p::proposal &winning_prop = winning_group.front(); + LOG_DEBUG << "Closing ledger with proposal:" << winning_prop.root_hash; // Upon successful ledger close condition, update the ledger and execute the contract using the consensus proposal. consensed_user_map consensed_users; - if (prepare_consensed_users(consensed_users, majority_prop) == -1 || - commit_consensus_results(majority_prop, consensed_users) == -1) + if (prepare_consensed_users(consensed_users, winning_prop) == -1 || + commit_consensus_results(winning_prop, consensed_users) == -1) { LOG_ERROR << "Error occured when closing ledger"; @@ -919,7 +912,12 @@ namespace consensus p.last_primary_shard_id = last_primary_shard_id; p.last_raw_shard_id = last_raw_shard_id; p.time_config = CURRENT_TIME_CONFIG; - crypto::random_bytes(p.nonce, ROUND_NONCE_SIZE); + + // In stage 0 proposals, we calculate a random nonce from this node to contribute to the group nonce + std::string rand_bytes; + crypto::random_bytes(rand_bytes, ledger::ROUND_NONCE_SIZE); + ctx.round_nonce = crypto::get_hash(rand_bytes); + p.node_nonce = ctx.round_nonce; // Populate the proposal with set of candidate user pubkeys. p.users.swap(ctx.candidate_users); @@ -940,19 +938,24 @@ namespace consensus { // The proposal to be emited at the end of this stage. p2p::proposal p; - p.stage = ctx.stage; + // We always vote for our current information regardless of what other peers are saying. // If there's a fork condition we will either request shards or hpfs state from // our peers or we will halt depending on level of consensus on the sides of the fork. + p.stage = ctx.stage; p.state_hash = state_hash; p.patch_hash = patch_hash; p.last_primary_shard_id = last_primary_shard_id; p.last_raw_shard_id = last_raw_shard_id; p.time_config = CURRENT_TIME_CONFIG; p.output_hash.resize(BLAKE3_OUT_LEN); // Default empty hash. + p.node_nonce = ctx.round_nonce; const uint64_t time_now = util::get_epoch_milliseconds(); + // Collect ordered nonces from all proposals in order to calculate the group nonce. + std::set node_nonces; + // Vote for rest of the proposal fields by looking at candidate proposals. for (const auto &[pubkey, cp] : ctx.candidate_proposals) { @@ -961,9 +964,6 @@ namespace consensus if (time_now > cp.time && (time_now - cp.time) <= (conf::cfg.contract.consensus.roundtime * 2)) increment(votes.time, cp.time); - // Vote for round nonce. - increment(votes.nonce, cp.nonce); - // Vote for user pubkeys. for (const std::string &pubkey : cp.users) increment(votes.users, pubkey); @@ -975,8 +975,14 @@ namespace consensus // Vote for contract output hash. increment(votes.output_hash, cp.output_hash); + + if (ctx.stage == 3) + node_nonces.emplace(cp.node_nonce.to_string_view()); } + if (ctx.stage == 3) + p.group_nonce = crypto::get_list_hash(node_nonces); + // Compute the stage tresholds using ratios. // Threshold is devided by 100 to convert average to decimal. const float stage_threshold = ((STAGE_THRESHOLD_RATIO[ctx.stage - 1] * conf::cfg.contract.consensus.threshold) / (STAGE_THRESHOLD_RATIO[2] * 100.0)); @@ -1043,17 +1049,6 @@ namespace consensus if (p.time == 0) p.time = ctx.round_start_time; - // Round nonce is voted on a simple sorted (highest to lowest) and majority basis, since there will always be disagreement. - uint32_t highest_nonce_vote = 0; - for (const auto [nonce, numvotes] : votes.nonce) - { - if (numvotes > highest_nonce_vote) - { - highest_nonce_vote = numvotes; - p.nonce = nonce; - } - } - return p; } diff --git a/src/consensus.hpp b/src/consensus.hpp index 34a20b7c..11434779 100644 --- a/src/consensus.hpp +++ b/src/consensus.hpp @@ -87,7 +87,6 @@ namespace consensus { // The map of proposals that are being collected as consensus stages are progressing. // peer public key is the key. - // todo: having a queue of proposals against peer pubkey. std::unordered_map candidate_proposals; // Set of user pubkeys that is said to be connected to the cluster. This will be cleared in each round. @@ -113,6 +112,7 @@ namespace consensus uint32_t stage_reset_wait_threshold = 0; // Minimum stage wait time to reset the stage. uint64_t round_boundry_offset = 0; // Time window boundry offset based on contract id. uint16_t unreliable_votes_attempts = 0; // No. of times we failed to get reliable votes continously. + util::h32 round_nonce; // The random nonce generated by this node for this consensus round. // Indicates whether we are inside a sync cycle or not. Sync cycle is considered to being when we first detect that we are out of sync // and considered to end when we detect to be in sync inside stage 1 of a round for the first time after we began a sync. @@ -132,7 +132,6 @@ namespace consensus struct vote_counter { std::map time; - std::map nonce; std::map lcl; std::map users; std::map inputs; @@ -145,7 +144,6 @@ namespace consensus void reset() { time.clear(); - nonce.clear(); lcl.clear(); users.clear(); inputs.clear(); diff --git a/src/ledger/ledger.cpp b/src/ledger/ledger.cpp index 269ad7cc..a1e6661b 100644 --- a/src/ledger/ledger.cpp +++ b/src/ledger/ledger.cpp @@ -41,7 +41,7 @@ namespace ledger /** * Perform ledger related initializations. - */ + */ int init() { // Setup the static genesis ledger fields. @@ -91,7 +91,7 @@ namespace ledger /** * Perform deinit tasks related to ledger. - */ + */ void deinit() { ledger_sync_worker.deinit(); @@ -247,6 +247,7 @@ namespace ledger data.emplace_back((char *)time_bytes, sizeof(time_bytes)); data.push_back(proposal.state_hash.to_string_view()); data.push_back(proposal.patch_hash.to_string_view()); + data.push_back(proposal.group_nonce.to_string_view()); data.push_back(user_hash); data.push_back(input_hash); data.push_back(proposal.output_hash); @@ -268,9 +269,11 @@ namespace ledger data_hash, std::string(proposal.state_hash.to_string_view()), std::string(proposal.patch_hash.to_string_view()), + std::string(proposal.group_nonce.to_string_view()), user_hash, input_hash, - proposal.output_hash}; // Merkle root output hash. + proposal.output_hash // Merkle root output hash. + }; if (sqlite::insert_ledger_row(db, ledger) == -1) { @@ -703,7 +706,7 @@ namespace ledger * @param last_shard_id Struct which holds last shard data. (sequence number and hash). * @param shard_parent_dir Parent director vpath of the shards. * @return 0 on success. -1 on error. - */ + */ int get_last_shard_info(std::string_view session_name, util::sequence_hash &last_shard_id, const std::string &shard_parent_dir) { const std::string last_shard_seq_no_vpath = shard_parent_dir + SHARD_SEQ_NO_FILENAME; @@ -746,12 +749,12 @@ namespace ledger } /** - * Update max_shard.seq_no meta file with the given latest shard sequence number which can be used to identify last shard + * Update max_shard.seq_no meta file with the given latest shard sequence number which can be used to identify last shard * sequence number in startup. * @param shard_parent_dir Shard's parent directory. (primary or raw). * @param last_shard_seq_no Last shard sequence number of the given parent. * @return Return -1 on error and 0 on success. - */ + */ int persist_max_shard_seq_no(const std::string &shard_parent_dir, const uint64_t last_shard_seq_no) { const std::string last_shard_seq_no_vpath = shard_parent_dir + SHARD_SEQ_NO_FILENAME; @@ -789,7 +792,7 @@ namespace ledger * @param root_hash The calculated root hash as of the given seq_no. * @param seq_no Ledger's sequence number. * @return Returns -1 on error and 0 on success. - */ + */ int get_root_hash_from_ledger(util::h32 &root_hash, const uint64_t seq_no) { sqlite3 *db = NULL; diff --git a/src/ledger/ledger_common.hpp b/src/ledger/ledger_common.hpp index 7ff57335..aff4fc38 100644 --- a/src/ledger/ledger_common.hpp +++ b/src/ledger/ledger_common.hpp @@ -12,6 +12,7 @@ namespace ledger constexpr const char *RAW_OUTPUTS_FILE = "raw_outputs.blob"; constexpr uint64_t PRIMARY_SHARD_SIZE = 262144; // 2^18 ledgers per shard. constexpr uint64_t RAW_SHARD_SIZE = 4096; + constexpr size_t ROUND_NONCE_SIZE = 64; /** * Holds an individual input for a user within a ledger. @@ -43,19 +44,24 @@ namespace ledger /** * Struct to hold ledger fields corresponding to sqlite table. * All the hashes are stored as 32 byte binary data. - */ + */ struct ledger_record { uint64_t seq_no = 0; uint64_t timestamp = 0; std::string ledger_hash; + + // COntributing hashes. std::string prev_ledger_hash; std::string data_hash; std::string state_hash; std::string config_hash; + std::string nonce; std::string user_hash; std::string input_hash; std::string output_hash; + + // Raw data. std::optional> inputs; std::optional> outputs; }; diff --git a/src/ledger/sqlite.cpp b/src/ledger/sqlite.cpp index 014b74e1..7dfda00f 100644 --- a/src/ledger/sqlite.cpp +++ b/src/ledger/sqlite.cpp @@ -35,8 +35,8 @@ namespace ledger::sqlite constexpr const char *INSERT_INTO_LEDGER = "INSERT INTO ledger(" "seq_no, time, ledger_hash, prev_ledger_hash, data_hash," - "state_hash, patch_hash, user_hash, input_hash, output_hash" - ") VALUES(?,?,?,?,?,?,?,?,?,?)"; + "state_hash, config_hash, nonce, user_hash, input_hash, output_hash" + ") VALUES(?,?,?,?,?,?,?,?,?,?,?)"; constexpr const char *INSERT_INTO_USERS = "INSERT INTO users(ledger_seq_no, pubkey) VALUES(?,?)"; constexpr const char *INSERT_INTO_USER_INPUTS = "INSERT INTO inputs(ledger_seq_no, pubkey, hash, nonce," " blob_offset, blob_size) VALUES(?,?,?,?,?,?)"; @@ -56,7 +56,7 @@ namespace ledger::sqlite * @param writable Whether the database must be opened in a writable mode or not. * @param journal Whether to enable db journaling or not. * @returns returns 0 on success, or -1 on error. - */ + */ int open_db(std::string_view db_name, sqlite3 **db, const bool writable, const bool journal) { int ret; @@ -84,7 +84,7 @@ namespace ledger::sqlite * @param callback Callback funcion which is called for each result row. * @param callback_first_arg First data argumat to be parced to the callback (void pointer). * @returns returns 0 on success, or -1 on error. - */ + */ int exec_sql(sqlite3 *db, std::string_view sql, int (*callback)(void *, int, char **, char **), void *callback_first_arg) { char *err_msg; @@ -118,7 +118,7 @@ namespace ledger::sqlite * @param table_name Table name to be created. * @param column_info Column info of the table. * @returns returns 0 on success, or -1 on error. - */ + */ int create_table(sqlite3 *db, std::string_view table_name, const std::vector &column_info) { std::string sql; @@ -186,7 +186,7 @@ namespace ledger::sqlite * @param column_names_string Comma seperated string of colums (eg: "col_1,col_2,..."). * @param value_strings Vector of comma seperated values (wrap in single quotes for TEXT type) (eg: ["r1val1,'r1val2',...", "r2val1,'r2val2',..."]). * @returns returns 0 on success, or -1 on error. - */ + */ int insert_rows(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, const std::vector &value_strings) { std::string sql; @@ -219,7 +219,7 @@ namespace ledger::sqlite * @param column_names_string Comma seperated string of colums (eg: "col_1,col_2,..."). * @param value_string comma seperated values as per column order (wrap in single quotes for TEXT type) (eg: "r1val1,'r1val2',..."). * @returns returns 0 on success, or -1 on error. - */ + */ int insert_row(sqlite3 *db, std::string_view table_name, std::string_view column_names_string, std::string_view value_string) { std::string sql; @@ -245,7 +245,7 @@ namespace ledger::sqlite * @param db Pointer to the db. * @param table_name Table name to be checked. * @returns returns true is exist, otherwise false. - */ + */ bool is_table_exists(sqlite3 *db, std::string_view table_name) { std::string sql; @@ -280,7 +280,7 @@ namespace ledger::sqlite * Closes a connection to a given databse. * @param db Pointer to the db. * @returns returns 0 on success, or -1 on error. - */ + */ int close_db(sqlite3 **db) { if (*db == NULL) @@ -300,7 +300,7 @@ namespace ledger::sqlite * Sets up a blank ledger database. * @param db Pointer to the db. * @returns returns 0 on success, or -1 on error. - */ + */ int initialize_ledger_db(sqlite3 *db) { const std::vector columns{ @@ -310,7 +310,8 @@ namespace ledger::sqlite table_column_info("prev_ledger_hash", COLUMN_DATA_TYPE::BLOB), table_column_info("data_hash", COLUMN_DATA_TYPE::BLOB), table_column_info("state_hash", COLUMN_DATA_TYPE::BLOB), - table_column_info("patch_hash", COLUMN_DATA_TYPE::BLOB), + table_column_info("config_hash", COLUMN_DATA_TYPE::BLOB), + table_column_info("nonce", COLUMN_DATA_TYPE::BLOB), table_column_info("user_hash", COLUMN_DATA_TYPE::BLOB), table_column_info("input_hash", COLUMN_DATA_TYPE::BLOB), table_column_info("output_hash", COLUMN_DATA_TYPE::BLOB)}; @@ -327,7 +328,7 @@ namespace ledger::sqlite * Sets up a blank ledger raw data database. * @param db Pointer to the db. * @returns returns 0 on success, or -1 on error. - */ + */ int initialize_ledger_raw_db(sqlite3 *db) { // Users table. @@ -383,8 +384,8 @@ namespace ledger::sqlite * @param db Pointer to the db. * @param version Version string to be placed in the table. * @returns returns 0 on success, or -1 on error. - * - */ + * + */ int create_hp_table(sqlite3 *db, std::string_view version) { const std::vector column_info{ @@ -405,7 +406,7 @@ namespace ledger::sqlite * @param db Pointer to the db. * @param ledger Ledger struct to be inserted. * @returns returns 0 on success, or -1 on error. - */ + */ int insert_ledger_row(sqlite3 *db, const ledger::ledger_record &ledger) { sqlite3_stmt *stmt; @@ -417,9 +418,10 @@ namespace ledger::sqlite BIND_H32_BLOB(5, ledger.data_hash) && BIND_H32_BLOB(6, ledger.state_hash) && BIND_H32_BLOB(7, ledger.config_hash) && - BIND_H32_BLOB(8, ledger.user_hash) && - BIND_H32_BLOB(9, ledger.input_hash) && - BIND_H32_BLOB(10, ledger.output_hash) && + BIND_H32_BLOB(8, ledger.nonce) && + BIND_H32_BLOB(9, ledger.user_hash) && + BIND_H32_BLOB(10, ledger.input_hash) && + BIND_H32_BLOB(11, ledger.output_hash) && sqlite3_step(stmt) == SQLITE_DONE) { sqlite3_finalize(stmt); @@ -533,7 +535,7 @@ namespace ledger::sqlite * @param db Pointer to the db. * @param ledger Ledger structure to populate. * @returns 0 on success. -1 on failure. - */ + */ int get_last_ledger(sqlite3 *db, ledger::ledger_record &ledger) { sqlite3_stmt *stmt; @@ -557,7 +559,7 @@ namespace ledger::sqlite * @param seq_no Ledger sequence no. to search for. * @param ledger Ledger structure to populate. * @returns 1 if ledger found. 0 if ledger not found. -1 on failure. - */ + */ int get_ledger_by_seq_no(sqlite3 *db, const uint64_t seq_no, ledger::ledger_record &ledger) { sqlite3_stmt *stmt; @@ -669,9 +671,10 @@ namespace ledger::sqlite ledger.data_hash = GET_H32_BLOB(4); ledger.state_hash = GET_H32_BLOB(5); ledger.config_hash = GET_H32_BLOB(6); - ledger.user_hash = GET_H32_BLOB(7); - ledger.input_hash = GET_H32_BLOB(8); - ledger.output_hash = GET_H32_BLOB(9); + ledger.nonce = GET_H32_BLOB(7); + ledger.user_hash = GET_H32_BLOB(8); + ledger.input_hash = GET_H32_BLOB(9); + ledger.output_hash = GET_H32_BLOB(10); } ledger::ledger_user_input populate_user_input_from_sql_record(sqlite3_stmt *stmt) diff --git a/src/msg/fbuf/p2pmsg.fbs b/src/msg/fbuf/p2pmsg.fbs index 1e14c585..14b91ca6 100644 --- a/src/msg/fbuf/p2pmsg.fbs +++ b/src/msg/fbuf/p2pmsg.fbs @@ -59,7 +59,8 @@ table ProposalMsg { stage:uint8; time:uint64; time_config:uint32; // Contains unified value derived from (roundtime*100 + stage_slice) - nonce: [ubyte]; + node_nonce: [ubyte]; + group_nonce: [ubyte]; users:[ByteArray]; input_hashes:[ByteArray]; output_hash:[ubyte]; diff --git a/src/msg/fbuf/p2pmsg_conversion.cpp b/src/msg/fbuf/p2pmsg_conversion.cpp index b6bd7fc8..ad67e652 100644 --- a/src/msg/fbuf/p2pmsg_conversion.cpp +++ b/src/msg/fbuf/p2pmsg_conversion.cpp @@ -77,13 +77,16 @@ namespace msg::fbuf::p2pmsg return util::h32_empty; } + /** + * Generate a hash using the consensus data fields of the proposal. + */ const util::h32 hash_proposal_msg(const msg::fbuf::p2pmsg::ProposalMsg &msg) { flatbuf_hasher hasher; hasher.add(msg.stage()); hasher.add(msg.time()); hasher.add(msg.time_config()); - hasher.add(msg.nonce()); + hasher.add(msg.group_nonce()); hasher.add(msg.users()); hasher.add(msg.input_hashes()); hasher.add(msg.output_hash()); @@ -149,7 +152,8 @@ namespace msg::fbuf::p2pmsg p.recv_timestamp = util::get_epoch_milliseconds(); p.time = msg.time(); p.time_config = msg.time_config(); - p.nonce = flatbuf_bytes_to_sv(msg.nonce()); + p.node_nonce = flatbuf_bytes_to_sv(msg.node_nonce()); + p.group_nonce = flatbuf_bytes_to_sv(msg.group_nonce()); p.stage = msg.stage(); p.state_hash = flatbuf_bytes_to_sv(msg.state_hash()); p.patch_hash = flatbuf_bytes_to_sv(msg.patch_hash()); @@ -335,7 +339,7 @@ namespace msg::fbuf::p2pmsg hasher.add(p.stage); hasher.add(p.time); hasher.add(p.time_config); - hasher.add(p.nonce); + hasher.add(p.group_nonce); hasher.add(p.users); hasher.add(p.input_ordered_hashes); hasher.add(p.output_hash); @@ -412,7 +416,8 @@ namespace msg::fbuf::p2pmsg p.stage, p.time, p.time_config, - sv_to_flatbuf_bytes(builder, p.nonce), + hash_to_flatbuf_bytes(builder, p.node_nonce), + hash_to_flatbuf_bytes(builder, p.group_nonce), stringlist_to_flatbuf_bytearrayvector(builder, p.users), stringlist_to_flatbuf_bytearrayvector(builder, p.input_ordered_hashes), sv_to_flatbuf_bytes(builder, p.output_hash), diff --git a/src/msg/fbuf/p2pmsg_generated.h b/src/msg/fbuf/p2pmsg_generated.h index ce8a99d9..e64ea9e2 100644 --- a/src/msg/fbuf/p2pmsg_generated.h +++ b/src/msg/fbuf/p2pmsg_generated.h @@ -954,15 +954,16 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_STAGE = 8, VT_TIME = 10, VT_TIME_CONFIG = 12, - VT_NONCE = 14, - VT_USERS = 16, - VT_INPUT_HASHES = 18, - VT_OUTPUT_HASH = 20, - VT_OUTPUT_SIG = 22, - VT_STATE_HASH = 24, - VT_PATCH_HASH = 26, - VT_LAST_PRIMARY_SHARD_ID = 28, - VT_LAST_RAW_SHARD_ID = 30 + VT_NODE_NONCE = 14, + VT_GROUP_NONCE = 16, + VT_USERS = 18, + VT_INPUT_HASHES = 20, + VT_OUTPUT_HASH = 22, + VT_OUTPUT_SIG = 24, + VT_STATE_HASH = 26, + VT_PATCH_HASH = 28, + VT_LAST_PRIMARY_SHARD_ID = 30, + VT_LAST_RAW_SHARD_ID = 32 }; const flatbuffers::Vector *pubkey() const { return GetPointer *>(VT_PUBKEY); @@ -994,11 +995,17 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool mutate_time_config(uint32_t _time_config) { return SetField(VT_TIME_CONFIG, _time_config, 0); } - const flatbuffers::Vector *nonce() const { - return GetPointer *>(VT_NONCE); + const flatbuffers::Vector *node_nonce() const { + return GetPointer *>(VT_NODE_NONCE); } - flatbuffers::Vector *mutable_nonce() { - return GetPointer *>(VT_NONCE); + flatbuffers::Vector *mutable_node_nonce() { + return GetPointer *>(VT_NODE_NONCE); + } + const flatbuffers::Vector *group_nonce() const { + return GetPointer *>(VT_GROUP_NONCE); + } + flatbuffers::Vector *mutable_group_nonce() { + return GetPointer *>(VT_GROUP_NONCE); } const flatbuffers::Vector> *users() const { return GetPointer> *>(VT_USERS); @@ -1057,8 +1064,10 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_STAGE) && VerifyField(verifier, VT_TIME) && VerifyField(verifier, VT_TIME_CONFIG) && - VerifyOffset(verifier, VT_NONCE) && - verifier.VerifyVector(nonce()) && + VerifyOffset(verifier, VT_NODE_NONCE) && + verifier.VerifyVector(node_nonce()) && + VerifyOffset(verifier, VT_GROUP_NONCE) && + verifier.VerifyVector(group_nonce()) && VerifyOffset(verifier, VT_USERS) && verifier.VerifyVector(users()) && verifier.VerifyVectorOfTables(users()) && @@ -1100,8 +1109,11 @@ struct ProposalMsgBuilder { void add_time_config(uint32_t time_config) { fbb_.AddElement(ProposalMsg::VT_TIME_CONFIG, time_config, 0); } - void add_nonce(flatbuffers::Offset> nonce) { - fbb_.AddOffset(ProposalMsg::VT_NONCE, nonce); + void add_node_nonce(flatbuffers::Offset> node_nonce) { + fbb_.AddOffset(ProposalMsg::VT_NODE_NONCE, node_nonce); + } + void add_group_nonce(flatbuffers::Offset> group_nonce) { + fbb_.AddOffset(ProposalMsg::VT_GROUP_NONCE, group_nonce); } void add_users(flatbuffers::Offset>> users) { fbb_.AddOffset(ProposalMsg::VT_USERS, users); @@ -1146,7 +1158,8 @@ inline flatbuffers::Offset CreateProposalMsg( uint8_t stage = 0, uint64_t time = 0, uint32_t time_config = 0, - flatbuffers::Offset> nonce = 0, + flatbuffers::Offset> node_nonce = 0, + flatbuffers::Offset> group_nonce = 0, flatbuffers::Offset>> users = 0, flatbuffers::Offset>> input_hashes = 0, flatbuffers::Offset> output_hash = 0, @@ -1165,7 +1178,8 @@ inline flatbuffers::Offset CreateProposalMsg( builder_.add_output_hash(output_hash); builder_.add_input_hashes(input_hashes); builder_.add_users(users); - builder_.add_nonce(nonce); + builder_.add_group_nonce(group_nonce); + builder_.add_node_nonce(node_nonce); builder_.add_time_config(time_config); builder_.add_sig(sig); builder_.add_pubkey(pubkey); @@ -1180,7 +1194,8 @@ inline flatbuffers::Offset CreateProposalMsgDirect( uint8_t stage = 0, uint64_t time = 0, uint32_t time_config = 0, - const std::vector *nonce = nullptr, + const std::vector *node_nonce = nullptr, + const std::vector *group_nonce = nullptr, const std::vector> *users = nullptr, const std::vector> *input_hashes = nullptr, const std::vector *output_hash = nullptr, @@ -1191,7 +1206,8 @@ inline flatbuffers::Offset CreateProposalMsgDirect( flatbuffers::Offset last_raw_shard_id = 0) { auto pubkey__ = pubkey ? _fbb.CreateVector(*pubkey) : 0; auto sig__ = sig ? _fbb.CreateVector(*sig) : 0; - auto nonce__ = nonce ? _fbb.CreateVector(*nonce) : 0; + auto node_nonce__ = node_nonce ? _fbb.CreateVector(*node_nonce) : 0; + auto group_nonce__ = group_nonce ? _fbb.CreateVector(*group_nonce) : 0; auto users__ = users ? _fbb.CreateVector>(*users) : 0; auto input_hashes__ = input_hashes ? _fbb.CreateVector>(*input_hashes) : 0; auto output_hash__ = output_hash ? _fbb.CreateVector(*output_hash) : 0; @@ -1205,7 +1221,8 @@ inline flatbuffers::Offset CreateProposalMsgDirect( stage, time, time_config, - nonce__, + node_nonce__, + group_nonce__, users__, input_hashes__, output_hash__, diff --git a/src/p2p/p2p.hpp b/src/p2p/p2p.hpp index ab5dc95e..2d7db49c 100644 --- a/src/p2p/p2p.hpp +++ b/src/p2p/p2p.hpp @@ -44,7 +44,8 @@ namespace p2p uint64_t time = 0; // The descreet concensus time value that is voted on. uint8_t stage = 0; // The round-stage that this proposal belongs to. uint32_t time_config = 0; // Time config of the proposer. - std::string nonce; // Random nonce that is used to reduce lcl predictability. + util::h32 node_nonce; // The random nonce produced by a particular node for the current consensus round. + util::h32 group_nonce; // The stage 3 canonical nonce (hash of all node nonces) which is used to salt the ledger. util::sequence_hash last_primary_shard_id; util::sequence_hash last_raw_shard_id; util::h32 state_hash; // Contract state hash. diff --git a/src/util/h32.hpp b/src/util/h32.hpp index deab6ac0..9984702b 100644 --- a/src/util/h32.hpp +++ b/src/util/h32.hpp @@ -5,7 +5,6 @@ namespace util { - // blake3b hash is 32 bytes which we store as 4 quad words // Originally from https://github.com/codetsunami/file-ptracer/blob/master/merkle.cpp struct h32 @@ -15,14 +14,17 @@ namespace util bool operator==(const h32 rhs) const; bool operator!=(const h32 rhs) const; void operator^=(const h32 rhs); - std::string_view to_string_view() const; h32 &operator=(std::string_view sv); void operator^=(std::string_view sv); bool operator<(const h32 rhs) const; + std::string_view to_string_view() const; h32() { - memset(data, 0, sizeof(data)); + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; } }; extern h32 h32_empty; diff --git a/src/util/version.hpp b/src/util/version.hpp index 51b74278..7cf6d3b5 100644 --- a/src/util/version.hpp +++ b/src/util/version.hpp @@ -6,13 +6,13 @@ namespace version { // HotPocket version. Written to new configs and p2p/user messages. - constexpr const char *HP_VERSION = "0.6.2"; + constexpr const char *HP_VERSION = "0.6.3"; // Minimum compatible config version (this will be used to validate configs). - constexpr const char *MIN_CONFIG_VERSION = "0.6.2"; + constexpr const char *MIN_CONFIG_VERSION = "0.6.3"; // Ledger file storage version. All nodes in a cluster MUST use the same ledger version. - constexpr const char *LEDGER_VERSION = "0.5.0"; + constexpr const char *LEDGER_VERSION = "0.6.3"; // Version header size in bytes when serialized in binary format. (applies to hp version as well as ledger version) // 2 bytes each for 3 version components. 2 bytes reserved. diff --git a/test/local-cluster/cluster-start.sh b/test/local-cluster/cluster-start.sh index b2e5e29a..8b7ea043 100755 --- a/test/local-cluster/cluster-start.sh +++ b/test/local-cluster/cluster-start.sh @@ -14,7 +14,7 @@ fi clusterloc=$(pwd)/hpcluster n=$1 -hpversion=0.6.1 +hpversion=0.6.3 let pubport=8080+$n let peerport=22860+$n diff --git a/test/local-cluster/consensus-test-continuous.sh b/test/local-cluster/consensus-test-continuous.sh index 55984391..bc914d52 100644 --- a/test/local-cluster/consensus-test-continuous.sh +++ b/test/local-cluster/consensus-test-continuous.sh @@ -5,7 +5,7 @@ WINDOWSIZE=60 # size of window in seconds to examine for successful consensus ro PIPE=concon.pipe clusterloc=$(pwd)/hpcluster n=1 -hpversion=0.6.1 +hpversion=0.6.3 let pubport=8080+$n while true; do diff --git a/test/local-cluster/consensus-test-loop.sh b/test/local-cluster/consensus-test-loop.sh index cac8d4d6..306e09a5 100644 --- a/test/local-cluster/consensus-test-loop.sh +++ b/test/local-cluster/consensus-test-loop.sh @@ -3,7 +3,7 @@ clusterloc=$(pwd)/hpcluster n=1 -hpversion=0.6.1 +hpversion=0.6.3 let pubport=8080+$n while true; do CONSENSUS="0" diff --git a/test/local-cluster/rundir.sh b/test/local-cluster/rundir.sh index ea8de4a2..087ced31 100755 --- a/test/local-cluster/rundir.sh +++ b/test/local-cluster/rundir.sh @@ -15,7 +15,7 @@ fi dir=$(realpath $1) dirname=$(basename $dir) n=$1 -hpversion=0.6.1 +hpversion=0.6.3 let pubport=8080