Skip to content

Commit

Permalink
The initial implementation of LoadLocalSideStakesFromConfig()
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescowens committed Oct 2, 2023
1 parent a4c5114 commit 02736aa
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 0 deletions.
133 changes: 133 additions & 0 deletions src/gridcoin/sidestake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ SideStakeRegistry& GRC::GetSideStakeRegistry()
return g_sidestake_entries;
}

// -----------------------------------------------------------------------------
// Class: CBitcoinAddressForStorage
// -----------------------------------------------------------------------------
CBitcoinAddressForStorage::CBitcoinAddressForStorage()
: CBitcoinAddress()
{}

CBitcoinAddressForStorage::CBitcoinAddressForStorage(CBitcoinAddress address)
: CBitcoinAddress(address)
{}

// -----------------------------------------------------------------------------
// Class: SideStake
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -434,6 +445,128 @@ uint64_t SideStakeRegistry::PassivateDB()
return m_sidestake_db.passivate_db();
}

void SideStakeRegistry::LoadLocalSideStakesFromConfig()
{
std::vector<SideStake> vSideStakes;
std::vector<std::pair<std::string, std::string>> raw_vSideStakeAlloc;
double dSumAllocation = 0.0;

// Parse destinations and allocations. We don't need to worry about any that are rejected other than a warning
// message, because any unallocated rewards will go back into the coinstake output(s).

// If -sidestakeaddresses and -sidestakeallocations is set in either the config file or the r-w settings file
// and the settings are not empty and they are the same size, this will take precedence over the multiple entry
// -sidestake format.
std::vector<std::string> addresses;
std::vector<std::string> allocations;

ParseString(gArgs.GetArg("-sidestakeaddresses", ""), ',', addresses);
ParseString(gArgs.GetArg("-sidestakeallocations", ""), ',', allocations);

if (addresses.size() != allocations.size())
{
LogPrintf("WARN: %s: Malformed new style sidestaking configuration entries. Reverting to original format.",
__func__);
}

if (addresses.size() && addresses.size() == allocations.size())
{
for (unsigned int i = 0; i < addresses.size(); ++i)
{
raw_vSideStakeAlloc.push_back(std::make_pair(addresses[i], allocations[i]));
}
}
else if (gArgs.GetArgs("-sidestake").size())
{
for (auto const& sSubParam : gArgs.GetArgs("-sidestake"))
{
std::vector<std::string> vSubParam;

ParseString(sSubParam, ',', vSubParam);
if (vSubParam.size() != 2)
{
LogPrintf("WARN: %s: Incomplete SideStake Allocation specified. Skipping SideStake entry.", __func__);
continue;
}

raw_vSideStakeAlloc.push_back(std::make_pair(vSubParam[0], vSubParam[1]));
}
}

for (const auto& entry : raw_vSideStakeAlloc)
{
std::string sAddress;
double dAllocation = 0.0;

sAddress = entry.first;

CBitcoinAddress address(sAddress);
if (!address.IsValid())
{
LogPrintf("WARN: %s: ignoring sidestake invalid address %s.", __func__, sAddress);
continue;
}

if (!ParseDouble(entry.second, &dAllocation))
{
LogPrintf("WARN: %s: Invalid allocation %s provided. Skipping allocation.", __func__, entry.second);
continue;
}

dAllocation /= 100.0;

if (dAllocation <= 0)
{
LogPrintf("WARN: %s: Negative or zero allocation provided. Skipping allocation.", __func__);
continue;
}

// The below will stop allocations if someone has made a mistake and the total adds up to more than 100%.
// Note this same check is also done in SplitCoinStakeOutput, but it needs to be done here for two reasons:
// 1. Early alertment in the debug log, rather than when the first kernel is found, and 2. When the UI is
// hooked up, the SideStakeAlloc vector will be filled in by other than reading the config file and will
// skip the above code.
dSumAllocation += dAllocation;
if (dSumAllocation > 1.0)
{
LogPrintf("WARN: %s: allocation percentage over 100 percent, ending sidestake allocations.", __func__);
break;
}

SideStake sidestake(static_cast<CBitcoinAddressForStorage>(address), dAllocation, 0, uint256{});

// This will add or update (replace) a non-contract entry in the registry for the local sidestake.
NonContractAdd(sidestake);

// This is needed because we need to detect entries in the registry map that are no longer in the config file to mark
// them deleted.
vSideStakes.push_back(sidestake);

LogPrint(BCLog::LogFlags::MINER, "INFO: %s: SideStakeAlloc Address %s, Allocation %f",
__func__, sAddress, dAllocation);
}

for (auto& entry : m_sidestake_entries)
{
// Only look at active entries. The others are NA for this alignment.
if (entry.second->m_status == SideStakeStatus::ACTIVE) {
auto iter = std::find(vSideStakes.begin(), vSideStakes.end(), *entry.second);

if (iter == vSideStakes.end()) {
// Entry in map is no longer found in config files, so mark map entry deleted.

entry.second->m_status = SideStakeStatus::DELETED;
}
}
}

// If we get here and dSumAllocation is zero then the enablesidestaking flag was set, but no VALID distribution
// was provided in the config file, so warn in the debug log.
if (!dSumAllocation)
LogPrintf("WARN: %s: enablesidestaking was set in config but nothing has been allocated for"
" distribution!", __func__);
}

SideStakeRegistry::SideStakeDB &SideStakeRegistry::GetSideStakeDB()
{
return m_sidestake_db;
Expand Down
11 changes: 11 additions & 0 deletions src/gridcoin/sidestake.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ namespace GRC {
class CBitcoinAddressForStorage : public CBitcoinAddress
{
public:
CBitcoinAddressForStorage();

CBitcoinAddressForStorage(CBitcoinAddress address);

ADD_SERIALIZE_METHODS;

Expand Down Expand Up @@ -419,6 +422,7 @@ class SideStakeRegistry : public IContractHandler
//!
//! \brief Allows local (voluntary) sidestakes to be added to the in-memory map and not persisted to
//! the registry db.
//!
//! \param SideStake object to add
//!
void NonContractAdd(SideStake& sidestake);
Expand All @@ -427,6 +431,7 @@ class SideStakeRegistry : public IContractHandler
//! \brief Add a sidestake entry to the registry from contract data. For the sidestake registry
//! both Add and Delete actually call a common helper function AddDelete, because the action
//! is actually symmetric to both.
//!
//! \param ctx
//!
void Add(const ContractContext& ctx) override;
Expand Down Expand Up @@ -499,6 +504,12 @@ class SideStakeRegistry : public IContractHandler
//!
uint64_t PassivateDB();

//!
//! \brief This method parses the config file for local sidestakes. It is based on the original GetSideStakingStatusAndAlloc()
//! that was in miner.cpp prior to the implementation of the SideStake class.
//!
void LoadLocalSideStakesFromConfig();

//!
//! \brief A static function that is called by the scheduler to run the sidestake entry database passivation.
//!
Expand Down

0 comments on commit 02736aa

Please sign in to comment.