mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
State synchronization logic (#67)
* Added flat buffer state message request * Added state vote * Added state to ledger history and did necessary changes * Completed receiveing state request * State read/write helpers. * Added new fbs schema * Added more state_store helper methods. * Started processing response * Fixed compile errors * Added get file length. * Handled state content response * Statefs code cleanup and fixes. * Completed response handling * Completed changes in handling state response * State sync integration fixes. * Fuse mount waiting logic. * Fixed state syncing issues * state sync fixes * fixes * State sync fixes. * Fixed fs entries retrieval issues. * changed desync logic * Added directory helper functions. * Handled return statemetns from statefs * Fixed state folder deletion. * handled errors from statefs * Working for small files * Got state sync working. * Removed cout. * Fixed catering for stae issue * Fixed block hash map flatbuf issue. * Added expected hash * Added helpers for expected hash comparison. * Improved state req/resp awaiting logic. * Fixes. * Fixes. * Block request ordering fix. * Removed couts * Closed non-closed file descriptors * Minor fixes. * Cluster create script changes. * Fixed reset time off issue.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "../conf.hpp"
|
||||
#include "../crypto.hpp"
|
||||
#include "../p2p/p2p.hpp"
|
||||
#include "../fbschema/common_helpers.hpp"
|
||||
#include "../fbschema/ledger_helpers.hpp"
|
||||
#include "../fbschema/p2pmsg_helpers.hpp"
|
||||
#include "ledger_handler.hpp"
|
||||
@@ -59,7 +60,10 @@ const std::tuple<const uint64_t, std::string> save_ledger(const p2p::proposal &p
|
||||
|
||||
write_ledger(file_name, ledger_str.data(), ledger_str.size());
|
||||
|
||||
cons::ctx.lcl_list.emplace(led_seq_no, file_name);
|
||||
ledger_cache c;
|
||||
c.lcl = file_name;
|
||||
c.state = proposal.curr_hash_state;
|
||||
cons::ctx.cache.emplace(led_seq_no, std::move(c));
|
||||
|
||||
//Remove old ledgers that exceeds max sequence range.
|
||||
if (led_seq_no > MAX_LEDGER_SEQUENCE)
|
||||
@@ -76,7 +80,7 @@ const std::tuple<const uint64_t, std::string> save_ledger(const p2p::proposal &p
|
||||
*/
|
||||
void remove_old_ledgers(const uint64_t led_seq_no)
|
||||
{
|
||||
std::map<uint64_t, std::string>::iterator itr;
|
||||
std::map<uint64_t, ledger_cache>::iterator itr;
|
||||
|
||||
std::string dir_path;
|
||||
|
||||
@@ -84,13 +88,13 @@ void remove_old_ledgers(const uint64_t led_seq_no)
|
||||
dir_path.append(conf::ctx.histdir)
|
||||
.append("/");
|
||||
|
||||
for (itr = cons::ctx.lcl_list.begin();
|
||||
itr != cons::ctx.lcl_list.lower_bound(led_seq_no + 1);
|
||||
for (itr = cons::ctx.cache.begin();
|
||||
itr != cons::ctx.cache.lower_bound(led_seq_no + 1);
|
||||
itr++)
|
||||
{
|
||||
const std::string file_name = itr->second;
|
||||
const std::string file_name = itr->second.lcl;
|
||||
std::string file_path;
|
||||
file_path.reserve(dir_path.size() + itr->second.size() + 4);
|
||||
file_path.reserve(dir_path.size() + itr->second.lcl.size() + 4);
|
||||
file_path.append(dir_path)
|
||||
.append(file_name)
|
||||
.append(".lcl");
|
||||
@@ -98,8 +102,9 @@ void remove_old_ledgers(const uint64_t led_seq_no)
|
||||
if (boost::filesystem::exists(file_path))
|
||||
boost::filesystem::remove(file_path);
|
||||
}
|
||||
if (!cons::ctx.lcl_list.empty())
|
||||
cons::ctx.lcl_list.erase(cons::ctx.lcl_list.begin(), cons::ctx.lcl_list.lower_bound(led_seq_no + 1));
|
||||
|
||||
if (!cons::ctx.cache.empty())
|
||||
cons::ctx.cache.erase(cons::ctx.cache.begin(), cons::ctx.cache.lower_bound(led_seq_no + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +159,7 @@ const ledger_history load_ledger()
|
||||
for (const auto &entry : boost::filesystem::directory_iterator(conf::ctx.histdir))
|
||||
{
|
||||
const boost::filesystem::path file_path = entry.path();
|
||||
const std::string file_name = entry.path().stem().string();
|
||||
const std::string file_name = file_path.stem().string();
|
||||
|
||||
if (boost::filesystem::is_directory(file_path))
|
||||
{
|
||||
@@ -172,7 +177,22 @@ const ledger_history load_ledger()
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
seq_no = std::stoull(file_name.substr(0, pos));
|
||||
ldg_hist.lcl_list.emplace(seq_no, file_name); //lcl -> [seq_no-hash]
|
||||
|
||||
std::ifstream file(file_path.string(), std::ios::binary | std::ios::ate);
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<char> buffer(size);
|
||||
if (file.read(buffer.data(), size))
|
||||
{
|
||||
const uint8_t *ledger_buf_ptr = reinterpret_cast<const uint8_t *>(buffer.data());
|
||||
const fbschema::ledger::Ledger *ledger = fbschema::ledger::GetLedger(ledger_buf_ptr);
|
||||
ledger_cache c;
|
||||
c.lcl = file_name;
|
||||
c.state = fbschema::flatbuff_bytes_to_sv(ledger->state());
|
||||
|
||||
ldg_hist.cache.emplace(seq_no, std::move(c)); //lcl_cache -> [seq_no-hash]
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -183,15 +203,15 @@ const ledger_history load_ledger()
|
||||
}
|
||||
|
||||
//check if there is a saved lcl file -> if no send genesis lcl.
|
||||
if (ldg_hist.lcl_list.empty())
|
||||
if (ldg_hist.cache.empty())
|
||||
{
|
||||
ldg_hist.led_seq_no = 0;
|
||||
ldg_hist.lcl = "0-genesis";
|
||||
}
|
||||
else
|
||||
{
|
||||
ldg_hist.led_seq_no = ldg_hist.lcl_list.rbegin()->first;
|
||||
ldg_hist.lcl = ldg_hist.lcl_list.rbegin()->second;
|
||||
ldg_hist.led_seq_no = ldg_hist.cache.rbegin()->first;
|
||||
ldg_hist.lcl = ldg_hist.cache.rbegin()->second.lcl;
|
||||
|
||||
//Remove old ledgers that exceeds max sequence range.
|
||||
if (ldg_hist.led_seq_no > MAX_LEDGER_SEQUENCE)
|
||||
@@ -241,15 +261,15 @@ bool check_required_lcl_availability(const p2p::history_request &hr)
|
||||
|
||||
if (req_seq_no > 0)
|
||||
{
|
||||
const auto itr = cons::ctx.lcl_list.find(req_seq_no);
|
||||
if (itr == cons::ctx.lcl_list.end())
|
||||
const auto itr = cons::ctx.cache.find(req_seq_no);
|
||||
if (itr == cons::ctx.cache.end())
|
||||
{
|
||||
LOG_DBG << "Required lcl peer asked for is not in our lcl cache.";
|
||||
//either this node is also not in consesnsus ledger or other node requesting a lcl that is older than node's current
|
||||
// minimum lcl sequence becuase of maximum ledger history range.
|
||||
return false;
|
||||
}
|
||||
else if (itr->second != hr.required_lcl)
|
||||
else if (itr->second.lcl != hr.required_lcl)
|
||||
{
|
||||
LOG_DBG << "Required lcl peer asked for is not in our lcl cache.";
|
||||
//either this node or requesting node is in a fork condition.
|
||||
@@ -281,20 +301,20 @@ const p2p::history_response retrieve_ledger_history(const p2p::history_request &
|
||||
min_seq_no = std::stoull(hr.minimum_lcl.substr(0, pos)); //get required lcl sequence number
|
||||
}
|
||||
|
||||
const auto itr = cons::ctx.lcl_list.find(min_seq_no);
|
||||
if (itr != cons::ctx.lcl_list.end()) //requested minimum lcl is not in our lcl history cache
|
||||
const auto itr = cons::ctx.cache.find(min_seq_no);
|
||||
if (itr != cons::ctx.cache.end()) //requested minimum lcl is not in our lcl history cache
|
||||
{
|
||||
min_seq_no = itr->first;
|
||||
//check whether minimum lcl node ask for is same as this node's.
|
||||
//eventhough sequence number are same, lcl hash can be changed if one of node is in a fork condition.
|
||||
if (hr.minimum_lcl != itr->second)
|
||||
if (hr.minimum_lcl != itr->second.lcl)
|
||||
{
|
||||
LOG_DBG << "Invalid minimum ledger. Recieved min hash: " << min_lcl_hash << " Node hash: " << itr->second;
|
||||
LOG_DBG << "Invalid minimum ledger. Recieved min hash: "<< min_lcl_hash << " Node hash: " << itr->second.lcl;
|
||||
history_response.error = p2p::LEDGER_RESPONSE_ERROR::INVALID_MIN_LEDGER;
|
||||
return history_response;
|
||||
}
|
||||
}
|
||||
else if (min_seq_no > cons::ctx.lcl_list.rbegin()->first) //Recieved minimum lcl sequence is ahead of node's lcl sequence.
|
||||
else if (min_seq_no > cons::ctx.cache.rbegin()->first) //Recieved minimum lcl sequence is ahead of node's lcl sequence.
|
||||
{
|
||||
LOG_DBG << "Invalid minimum ledger. Recieved minimum sequence number is ahead of node current lcl sequence. hash: " << min_lcl_hash;
|
||||
history_response.error = p2p::LEDGER_RESPONSE_ERROR::INVALID_MIN_LEDGER;
|
||||
@@ -303,32 +323,32 @@ const p2p::history_response retrieve_ledger_history(const p2p::history_request &
|
||||
else
|
||||
{
|
||||
LOG_DBG << "Minimum lcl peer asked for is not in our lcl cache. Therefore sending from node minimum lcl";
|
||||
min_seq_no = cons::ctx.lcl_list.begin()->first;
|
||||
min_seq_no = cons::ctx.cache.begin()->first;
|
||||
}
|
||||
|
||||
//LOG_DBG << "history request min seq: " << std::to_string(min_seq_no);
|
||||
|
||||
//copy current history cache.
|
||||
std::map<uint64_t, std::string>
|
||||
lcl_list = cons::ctx.lcl_list;
|
||||
std::map<uint64_t, ledger_cache> led_cache = cons::ctx.cache;
|
||||
|
||||
//filter out cache from finalized minimum sequence.
|
||||
lcl_list.erase(
|
||||
lcl_list.begin(),
|
||||
lcl_list.lower_bound(min_seq_no));
|
||||
//filter out cache and get raw files here.
|
||||
led_cache.erase(
|
||||
led_cache.begin(),
|
||||
led_cache.lower_bound(min_seq_no));
|
||||
|
||||
//Get raw content of lcls that going to be send.
|
||||
for (auto &[seq_no, lcl_hash] : lcl_list)
|
||||
//Get raw content of lcls that going to be send.
|
||||
for (auto &[seq_no, cache] : led_cache)
|
||||
{
|
||||
p2p::history_ledger ledger;
|
||||
ledger.lcl = lcl_hash;
|
||||
ledger.lcl = cache.lcl;
|
||||
ledger.state = cache.state;
|
||||
|
||||
std::string path;
|
||||
|
||||
path.reserve(conf::ctx.histdir.size() + lcl_hash.size() + 5);
|
||||
path.reserve(conf::ctx.histdir.size() + cache.lcl.size() + 5);
|
||||
path.append(conf::ctx.histdir)
|
||||
.append("/")
|
||||
.append(lcl_hash)
|
||||
.append(cache.lcl)
|
||||
.append(".lcl");
|
||||
|
||||
//read lcl file
|
||||
@@ -379,7 +399,7 @@ void handle_ledger_history_response(const p2p::history_response &hr)
|
||||
// This means we are in a fork ledger.Remove/rollback current ledger.
|
||||
// Basically in the long run we'll rolback one by one untill we catch up to valid minimum ledger .
|
||||
remove_ledger(ctx.lcl);
|
||||
cons::ctx.lcl_list.erase(ctx.lcl_list.rbegin()->first);
|
||||
cons::ctx.cache.erase(ctx.cache.rbegin()->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -433,27 +453,34 @@ void handle_ledger_history_response(const p2p::history_response &hr)
|
||||
//Save recieved lcl in file system and update lcl history cache
|
||||
for (auto &[seq_no, ledger] : hr.hist_ledgers)
|
||||
{
|
||||
auto prev_dup_itr = cons::ctx.lcl_list.find(seq_no);
|
||||
if (prev_dup_itr != cons::ctx.lcl_list.end())
|
||||
auto prev_dup_itr = cons::ctx.cache.find(seq_no);
|
||||
if (prev_dup_itr != cons::ctx.cache.end())
|
||||
{
|
||||
remove_ledger(prev_dup_itr->second);
|
||||
cons::ctx.lcl_list.erase(prev_dup_itr);
|
||||
remove_ledger(prev_dup_itr->second.lcl);
|
||||
cons::ctx.cache.erase(prev_dup_itr);
|
||||
}
|
||||
write_ledger(ledger.lcl, reinterpret_cast<const char *>(&ledger.raw_ledger[0]), ledger.raw_ledger.size());
|
||||
cons::ctx.lcl_list.emplace(seq_no, ledger.lcl);
|
||||
ledger_cache l;
|
||||
l.lcl = ledger.lcl;
|
||||
l.state = ledger.state;
|
||||
cons::ctx.cache.emplace(seq_no, std::move(l));
|
||||
}
|
||||
|
||||
last_requested_lcl = "";
|
||||
|
||||
const auto latest_lcl_itr = cons::ctx.cache.rbegin();
|
||||
cons::ctx.lcl = latest_lcl_itr->second.lcl;
|
||||
cons::ctx.led_seq_no = latest_lcl_itr->first;
|
||||
|
||||
if (cons::ctx.lcl_list.empty())
|
||||
if (cons::ctx.cache.empty())
|
||||
{
|
||||
cons::ctx.led_seq_no = 0;
|
||||
cons::ctx.lcl = "0-genesis";
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto latest_lcl_itr = cons::ctx.lcl_list.rbegin();
|
||||
cons::ctx.lcl = latest_lcl_itr->second;
|
||||
const auto latest_lcl_itr = cons::ctx.cache.rbegin();
|
||||
cons::ctx.lcl = latest_lcl_itr->second.lcl;
|
||||
cons::ctx.led_seq_no = latest_lcl_itr->first;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user