Skip to content

Commit

Permalink
Split out map for local sidstakes
Browse files Browse the repository at this point in the history
I realized that a change in design was necessary to split out the map
to hold local sidestakes, because it is possible that a local sidestake
could exist that pays to the same address as a mandatory sidestake.

It is much more correct, and simpler, to retain both instead of coming
up with complicated override rules.
  • Loading branch information
jamescowens committed Oct 5, 2023
1 parent 5d7ad93 commit 813d666
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 27 deletions.
98 changes: 81 additions & 17 deletions src/gridcoin/sidestake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "sidestake.h"
#include "node/ui_interface.h"
#include "univalue.h"

//!
//! \brief Model callback bound to the \c RwSettingsUpdated core signal.
Expand Down Expand Up @@ -222,7 +223,7 @@ const std::vector<SideStake_ptr> SideStakeRegistry::ActiveSideStakeEntries()
if (fEnableSideStaking) {
LogPrint(BCLog::LogFlags::MINER, "INFO: %s: fEnableSideStaking = %u", __func__, fEnableSideStaking);

for (const auto& entry : m_sidestake_entries)
for (const auto& entry : m_local_sidestake_entries)
{
if (entry.second->m_status == SideStakeStatus::ACTIVE && allocation_sum + entry.second->m_allocation <= 1.0) {
sidestakes.push_back(entry.second);
Expand All @@ -234,30 +235,42 @@ const std::vector<SideStake_ptr> SideStakeRegistry::ActiveSideStakeEntries()
return sidestakes;
}

SideStakeOption SideStakeRegistry::Try(const CBitcoinAddressForStorage& key) const
std::vector<SideStake_ptr> SideStakeRegistry::Try(const CBitcoinAddressForStorage& key, const bool& local_only) const
{
LOCK(cs_lock);

const auto iter = m_sidestake_entries.find(key);
std::vector<SideStake_ptr> result;

if (iter == m_sidestake_entries.end()) {
return nullptr;
if (!local_only) {
const auto mandatory_entry = m_sidestake_entries.find(key);

if (mandatory_entry != m_sidestake_entries.end()) {
result.push_back(mandatory_entry->second);
}
}

const auto local_entry = m_local_sidestake_entries.find(key);

if (local_entry != m_sidestake_entries.end()) {
result.push_back(local_entry->second);
}

return iter->second;
return result;
}

SideStakeOption SideStakeRegistry::TryActive(const CBitcoinAddressForStorage& key) const
std::vector<SideStake_ptr> SideStakeRegistry::TryActive(const CBitcoinAddressForStorage& key, const bool& local_only) const
{
LOCK(cs_lock);

if (const SideStakeOption SideStake_entry = Try(key)) {
if (SideStake_entry->m_status == SideStakeStatus::ACTIVE || SideStake_entry->m_status == SideStakeStatus::MANDATORY) {
return SideStake_entry;
std::vector<SideStake_ptr> result;

for (const auto& iter : Try(key, local_only)) {
if (iter->m_status == SideStakeStatus::MANDATORY || iter->m_status == SideStakeStatus::ACTIVE) {
result.push_back(iter);
}
}

return nullptr;
return result;
}

void SideStakeRegistry::Reset()
Expand Down Expand Up @@ -346,7 +359,9 @@ void SideStakeRegistry::AddDelete(const ContractContext& ctx)
void SideStakeRegistry::NonContractAdd(SideStake& sidestake)
{
// Using this form of insert because we want the latest record with the same key to override any previous one.
m_sidestake_entries[sidestake.m_key] = std::make_shared<SideStake>(sidestake);
m_local_sidestake_entries[sidestake.m_key] = std::make_shared<SideStake>(sidestake);


}

void SideStakeRegistry::Add(const ContractContext& ctx)
Expand All @@ -356,10 +371,10 @@ void SideStakeRegistry::Add(const ContractContext& ctx)

void SideStakeRegistry::NonContractDelete(CBitcoinAddressForStorage& address)
{
auto sidestake_entry_pair_iter = m_sidestake_entries.find(address);
auto sidestake_entry_pair_iter = m_local_sidestake_entries.find(address);

if (sidestake_entry_pair_iter != m_sidestake_entries.end()) {
m_sidestake_entries.erase(sidestake_entry_pair_iter);
if (sidestake_entry_pair_iter != m_local_sidestake_entries.end()) {
m_local_sidestake_entries.erase(sidestake_entry_pair_iter);
}
}

Expand Down Expand Up @@ -469,9 +484,11 @@ int SideStakeRegistry::Initialize()
LogPrint(LogFlags::CONTRACT, "INFO: %s: m_sidestake_db size after load: %u", __func__, m_sidestake_db.size());
LogPrint(LogFlags::CONTRACT, "INFO: %s: m_sidestake_entries size after load: %u", __func__, m_sidestake_entries.size());

// Add the local sidestakes specified in the config file(s) to the mandatory sidestakes.
// Add the local sidestakes specified in the config file(s) to the local sidestakes map.
LoadLocalSideStakesFromConfig();

m_local_entry_already_saved_to_config = false;

return height;
}

Expand All @@ -497,6 +514,7 @@ void SideStakeRegistry::ResetInMemoryOnly()
{
LOCK(cs_lock);

m_local_sidestake_entries.clear();
m_sidestake_entries.clear();
m_sidestake_db.clear_in_memory_only();
}
Expand All @@ -510,6 +528,16 @@ uint64_t SideStakeRegistry::PassivateDB()

void SideStakeRegistry::LoadLocalSideStakesFromConfig()
{
// If the m_local_entry_already_saved_to_config is set, then SaveLocalSideStakeToConfig was just called,
// and we want to then ignore the update signal from the r-w file change that calls this function for
// that action (only) and then reset the flag to be responsive to any changes on the core r-w file side
// through changesettings, for example.
if (m_local_entry_already_saved_to_config) {
m_local_entry_already_saved_to_config = false;

return;
}

std::vector<SideStake> vSideStakes;
std::vector<std::pair<std::string, std::string>> raw_vSideStakeAlloc;
double dSumAllocation = 0.0;
Expand Down Expand Up @@ -624,7 +652,7 @@ void SideStakeRegistry::LoadLocalSideStakesFromConfig()
__func__, sAddress, dAllocation);
}

for (auto& entry : m_sidestake_entries)
for (auto& entry : m_local_sidestake_entries)
{
// Only look at active entries. The others are NA for this alignment.
if (entry.second->m_status == SideStakeStatus::ACTIVE) {
Expand All @@ -645,6 +673,42 @@ void SideStakeRegistry::LoadLocalSideStakesFromConfig()
" distribution!", __func__);
}

bool SideStakeRegistry::SaveLocalSideStakesToConfig()
{
bool status = false;

std::string addresses;
std::string allocations;
std::string descriptions;

std::string separator;

std::vector<std::pair<std::string, util::SettingsValue>> settings;

unsigned int i = 0;
for (const auto& iter : m_local_sidestake_entries) {
if (i) {
separator = ",";
}

addresses += separator + iter.second->m_key.ToString();
allocations += separator + ToString(iter.second->m_allocation * 100.0);
descriptions += separator + iter.second->m_description;

++i;
}

settings.push_back(std::make_pair("addresses", addresses));
settings.push_back(std::make_pair("allocations", allocations));
settings.push_back(std::make_pair("descriptions", descriptions));

status = updateRwSettings(settings);

m_local_entry_already_saved_to_config = true;

return status;
}

void SideStakeRegistry::SubscribeToCoreSignals()
{
uiInterface.RwSettingsUpdated_connect(std::bind(RwSettingsUpdated, this));
Expand Down
30 changes: 22 additions & 8 deletions src/gridcoin/sidestake.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ typedef std::shared_ptr<SideStake> SideStake_ptr;
//!
//! \brief A type that either points to some sidestake or does not.
//!
typedef const SideStake_ptr SideStakeOption;
//typedef const SideStake_ptr SideStakeOption;

//!
//! \brief The body of a sidestake entry contract. Note that this body is bimodal. It
Expand Down Expand Up @@ -416,21 +416,24 @@ class SideStakeRegistry : public IContractHandler
//! \brief Get the current sidestake entry for the specified key string.
//!
//! \param key The key string of the sidestake entry.
//! \param local_only If true causes Try to only check the local sidestake map. Defaults to false.
//!
//! \return An object that either contains a reference to some sidestake entry if it exists
//! for the key or does not.
//! \return A vector of smart pointers to entries matching the provided key (address). Up to two elements
//! are returned, mandatory entry first, unless local only boolean is set true.
//!
SideStakeOption Try(const CBitcoinAddressForStorage& key) const;
std::vector<SideStake_ptr> Try(const CBitcoinAddressForStorage& key, const bool& local_only = false) const;

//!
//! \brief Get the current sidestake entry for the specified key string if it has a status of ACTIVE or MANDATORY.
//!
//! \param key The key string of the sidestake entry.
//! \param local_only If true causes Try to only check the local sidestake map. Defaults to false.
//!
//! \return An object that either contains a reference to some sidestake entry if it exists
//! for the key and is in the required status or does not.
//! \return A vector of smart pointers to entries matching the provided key (address) that are in status of
//! MANDATORY or ACTIVE. Up to two elements are returned, mandatory entry first, unless local only boolean
//! is set true.
//!
SideStakeOption TryActive(const CBitcoinAddressForStorage& key) const;
std::vector<SideStake_ptr> TryActive(const CBitcoinAddressForStorage& key, const bool& local_only = false) const;

//!
//! \brief Destroy the contract handler state in case of an error in loading
Expand Down Expand Up @@ -584,14 +587,25 @@ class SideStakeRegistry : public IContractHandler
//!
void AddDelete(const ContractContext& ctx);

//!
//! \brief Private helper function for non-contract add and delete to align the config r-w file with
//! in memory local sidestake map.
//!
//! \return bool true if successful.
//!
bool SaveLocalSideStakesToConfig();

void SubscribeToCoreSignals();
void UnsubscribeFromCoreSignals();

SideStakeMap m_sidestake_entries; //!< Contains the current sidestake entries including entries marked DELETED.
SideStakeMap m_local_sidestake_entries; //!< Contains the local (non-contract) sidestake entries.
SideStakeMap m_sidestake_entries; //!< Contains the mandatory sidestake entries, including DELETED.
PendingSideStakeMap m_pending_sidestake_entries {}; //!< Not used. Only to satisfy the template.

SideStakeDB m_sidestake_db;

bool m_local_entry_already_saved_to_config = false; //!< Flag to prevent reload on signal if individual entry saved already.

public:

SideStakeDB& GetSideStakeDB();
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ UniValue getstakinginfo(const UniValue& params, bool fHelp)

bool fEnableSideStaking = gArgs.GetBoolArg("-enablesidestaking");

if (fEnableSideStaking) vSideStakeAlloc = GRC::GetSideStakeRegistry().ActiveSideStakeEntries();

stakesplitting.pushKV("stake-splitting-enabled", fEnableStakeSplit);
if (fEnableStakeSplit)
{
Expand All @@ -110,6 +108,8 @@ UniValue getstakinginfo(const UniValue& params, bool fHelp)
}
obj.pushKV("stake-splitting", stakesplitting);

vSideStakeAlloc = GRC::GetSideStakeRegistry().ActiveSideStakeEntries();

sidestaking.pushKV("local_side_staking_enabled", fEnableSideStaking);

// Note that if local_side_staking_enabled is true, then local sidestakes will be applicable and shown. Mandatory
Expand Down

0 comments on commit 813d666

Please sign in to comment.