diff --git a/src/gridcoin/sidestake.cpp b/src/gridcoin/sidestake.cpp index 45eea5e7f1..1472469523 100644 --- a/src/gridcoin/sidestake.cpp +++ b/src/gridcoin/sidestake.cpp @@ -53,13 +53,17 @@ SideStake::SideStake(CBitcoinAddressForStorage address, double allocation) , m_status(SideStakeStatus::UNKNOWN) {} -SideStake::SideStake(CBitcoinAddressForStorage address, double allocation, int64_t timestamp, uint256 hash) +SideStake::SideStake(CBitcoinAddressForStorage address, + double allocation, + int64_t timestamp, + uint256 hash, + SideStakeStatus status) : m_key(address) , m_allocation(allocation) , m_timestamp(timestamp) , m_hash(hash) , m_previous_hash() - , m_status(SideStakeStatus::UNKNOWN) + , m_status(status) {} bool SideStake::WellFormed() const @@ -145,10 +149,13 @@ SideStakePayload::SideStakePayload(uint32_t version) { } -SideStakePayload::SideStakePayload(const uint32_t version, CBitcoinAddressForStorage key, double value, SideStakeStatus status) +SideStakePayload::SideStakePayload(const uint32_t version, + CBitcoinAddressForStorage key, + double value, + SideStakeStatus status) : IContractPayload() , m_version(version) - , m_entry(SideStake(key, value, status)) + , m_entry(SideStake(key, value, 0, uint256{}, status)) { } @@ -547,7 +554,11 @@ void SideStakeRegistry::LoadLocalSideStakesFromConfig() break; } - SideStake sidestake(static_cast(address), dAllocation, 0, uint256{}); + SideStake sidestake(static_cast(address), + dAllocation, + 0, + uint256{}, + SideStakeStatus::ACTIVE); // This will add or update (replace) a non-contract entry in the registry for the local sidestake. NonContractAdd(sidestake); diff --git a/src/gridcoin/sidestake.h b/src/gridcoin/sidestake.h index 9ac2090236..44dda7157f 100644 --- a/src/gridcoin/sidestake.h +++ b/src/gridcoin/sidestake.h @@ -106,8 +106,9 @@ class SideStake //! \param allocation //! \param timestamp //! \param hash + //! \param status //! - SideStake(CBitcoinAddressForStorage address, double allocation, int64_t timestamp, uint256 hash); + SideStake(CBitcoinAddressForStorage address, double allocation, int64_t timestamp, uint256 hash, SideStakeStatus status); //! //! \brief Determine whether a sidestake contains each of the required elements. diff --git a/src/miner.cpp b/src/miner.cpp index c7c1cde861..9584982c9a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -922,24 +922,26 @@ void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStake (iterSideStake != vSideStakeAlloc.end()) && (nOutputsUsed <= nMaxSideStakeOutputs); ++iterSideStake) { - CBitcoinAddress address(iterSideStake->first); + CBitcoinAddress& address = iterSideStake->get()->m_key; if (!address.IsValid()) { LogPrintf("WARN: SplitCoinStakeOutput: ignoring sidestake invalid address %s.", - iterSideStake->first.c_str()); + iterSideStake->get()->m_key.ToString()); continue; } // Do not process a distribution that would result in an output less than 1 CENT. This will flow back into // the coinstake below. Prevents dust build-up. - if (nReward * iterSideStake->second < CENT) + if (nReward * iterSideStake->get()->m_allocation < CENT) { LogPrintf("WARN: SplitCoinStakeOutput: distribution %f too small to address %s.", - CoinToDouble(nReward * iterSideStake->second), iterSideStake->first.c_str()); + CoinToDouble(nReward * iterSideStake->get()->m_allocation), + iterSideStake->get()->m_key.ToString() + ); continue; } - if (dSumAllocation + iterSideStake->second > 1.0) + if (dSumAllocation + iterSideStake->get()->m_allocation > 1.0) { LogPrintf("WARN: SplitCoinStakeOutput: allocation percentage over 100 percent, " "ending sidestake allocations."); @@ -962,11 +964,11 @@ void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStake int64_t nSideStake = 0; // For allocations ending less than 100% assign using sidestake allocation. - if (dSumAllocation + iterSideStake->second < 1.0) - nSideStake = nReward * iterSideStake->second; + if (dSumAllocation + iterSideStake->get()->m_allocation < 1.0) + nSideStake = nReward * iterSideStake->get()->m_allocation; // We need to handle the final sidestake differently in the case it brings the total allocation up to 100%, // because testing showed in corner cases the output return to the staking address could be off by one Halford. - else if (dSumAllocation + iterSideStake->second == 1.0) + else if (dSumAllocation + iterSideStake->get()->m_allocation == 1.0) // Simply assign the special case final nSideStake the remaining output value minus input value to ensure // a match on the output flowing down. nSideStake = nRemainingStakeOutputValue - nInputValue; @@ -974,8 +976,11 @@ void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStake blocknew.vtx[1].vout.push_back(CTxOut(nSideStake, SideStakeScriptPubKey)); LogPrintf("SplitCoinStakeOutput: create sidestake UTXO %i value %f to address %s", - nOutputsUsed, CoinToDouble(nReward * iterSideStake->second), iterSideStake->first.c_str()); - dSumAllocation += iterSideStake->second; + nOutputsUsed, + CoinToDouble(nReward * iterSideStake->get()->m_allocation), + iterSideStake->get()->m_key.ToString() + ); + dSumAllocation += iterSideStake->get()->m_allocation; nRemainingStakeOutputValue -= nSideStake; nOutputsUsed++; } @@ -1249,110 +1254,6 @@ bool IsMiningAllowed(CWallet *pwallet) return g_miner_status.StakingEnabled(); } -// This function parses the config file for the directives for side staking. It is used -// in StakeMiner for the miner loop and also called by rpc getstakinginfo. -SideStakeAlloc GetSideStakingStatusAndAlloc() -{ - SideStakeAlloc vSideStakeAlloc; - std::vector> 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 addresses; - std::vector 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 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 (auto const& 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; - } - - vSideStakeAlloc.push_back(std::pair(sAddress, dAllocation)); - LogPrint(BCLog::LogFlags::MINER, "INFO: %s: SideStakeAlloc Address %s, Allocation %f", - __func__, sAddress, dAllocation); - } - - // 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__); - - return vSideStakeAlloc; -} - // This function parses the config file for the directives for stake splitting. It is used // in StakeMiner for the miner loop and also called by rpc getstakinginfo. bool GetStakeSplitStatusAndParams(int64_t& nMinStakeSplitValue, double& dEfficiency, int64_t& nDesiredStakeOutputValue) @@ -1421,7 +1322,7 @@ void StakeMiner(CWallet *pwallet) LogPrint(BCLog::LogFlags::MINER, "INFO: %s: fEnableSideStaking = %u", __func__, fEnableSideStaking); // vSideStakeAlloc is an out parameter. - if (fEnableSideStaking) vSideStakeAlloc = GetSideStakingStatusAndAlloc(); + if (fEnableSideStaking) vSideStakeAlloc = GRC::GetSideStakeRegistry().ActiveSideStakeEntries(); // wait for next round if (!MilliSleep(nMinerSleep)) return; diff --git a/src/miner.h b/src/miner.h index 75223078e3..c713a8de89 100644 --- a/src/miner.h +++ b/src/miner.h @@ -8,11 +8,13 @@ #define BITCOIN_MINER_H #include "main.h" +#include "gridcoin/sidestake.h" + class CWallet; class CWalletTx; -typedef std::vector< std::pair > SideStakeAlloc; +typedef std::vector SideStakeAlloc; extern unsigned int nMinerSleep; @@ -24,7 +26,6 @@ static const int64_t MIN_STAKE_SPLIT_VALUE_GRC = 800; void SplitCoinStakeOutput(CBlock &blocknew, int64_t &nReward, bool &fEnableStakeSplit, bool &fEnableSideStaking, SideStakeAlloc &vSideStakeAlloc, double &dEfficiency); unsigned int GetNumberOfStakeOutputs(int64_t &nValue, int64_t &nMinStakeSplitValue, double &dEfficiency); -SideStakeAlloc GetSideStakingStatusAndAlloc(); bool GetStakeSplitStatusAndParams(int64_t& nMinStakeSplitValue, double& dEfficiency, int64_t& nDesiredStakeOutputValue); bool CreateMRCRewards(CBlock &blocknew, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 49f787e1b1..e692030356 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -98,7 +98,7 @@ UniValue getstakinginfo(const UniValue& params, bool fHelp) bool fEnableSideStaking = gArgs.GetBoolArg("-enablesidestaking"); - if (fEnableSideStaking) vSideStakeAlloc = GetSideStakingStatusAndAlloc(); + if (fEnableSideStaking) vSideStakeAlloc = GRC::GetSideStakeRegistry().ActiveSideStakeEntries(); stakesplitting.pushKV("stake-splitting-enabled", fEnableStakeSplit); if (fEnableStakeSplit) @@ -115,8 +115,8 @@ UniValue getstakinginfo(const UniValue& params, bool fHelp) { for (const auto& alloc : vSideStakeAlloc) { - sidestakingalloc.pushKV("address", alloc.first); - sidestakingalloc.pushKV("allocation-pct", alloc.second * 100); + sidestakingalloc.pushKV("address", alloc->m_key.ToString()); + sidestakingalloc.pushKV("allocation-pct", alloc->m_allocation * 100); vsidestakingalloc.push_back(sidestakingalloc); }