diff --git a/src/init.cpp b/src/init.cpp index 7c3e53aea6..c1b19a128b 100755 --- a/src/init.cpp +++ b/src/init.cpp @@ -363,8 +363,21 @@ void SetupServerArgs() argsman.AddArg("-sidestake=", "Sidestake destination and allocation entry. There can be as many " "specified as desired. Only six per stake can be sent. If more than " "six are specified. Six are randomly chosen for each stake. Only active " - "if -enablesidestaking is set.", - ArgsManager::ALLOW_ANY, OptionsCategory::STAKING); + "if -enablesidestaking is set. These settings are overridden if " + "-sidestakeaddresses and -stakestakeallocations are set.", + ArgsManager::ALLOW_ANY | ArgsManager::IMMEDIATE_EFFECT, OptionsCategory::STAKING); + argsman.AddArg("-sidestakeaddresses=", "Sidestake destination entry. There can be as many " + "specified as desired. Only six per stake can be sent. If more than " + "six are specified. Six are randomly chosen for each stake. Only active " + "if -enablesidestaking is set. If set along with -sidestakeallocations " + "overrides the -sidestake entries.", + ArgsManager::ALLOW_ANY | ArgsManager::IMMEDIATE_EFFECT, OptionsCategory::STAKING); + argsman.AddArg("-sidestakeallocations=percent1,percent2,...,percentN>", "Sidestake allocation entry. There can be as many " + "specified as desired. Only six per stake can be sent. If more than " + "six are specified. Six are randomly chosen for each stake. Only active " + "if -enablesidestaking is set. If set along with -sidestakeaddresses " + "overrides the -sidestake entries.", + ArgsManager::ALLOW_ANY | ArgsManager::IMMEDIATE_EFFECT, OptionsCategory::STAKING); argsman.AddArg("-enablestakesplit", "Enable unspent output spitting when staking to optimize staking efficiency " "(default: 0", ArgsManager::ALLOW_ANY | ArgsManager::IMMEDIATE_EFFECT, OptionsCategory::STAKING); diff --git a/src/miner.cpp b/src/miner.cpp index 443b914397..b5f23419ca 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1189,87 +1189,108 @@ bool IsMiningAllowed(CWallet *pwallet) // 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 getmininginfo. -bool GetSideStakingStatusAndAlloc(SideStakeAlloc& vSideStakeAlloc) +SideStakeAlloc GetSideStakingStatusAndAlloc() { - vector vSubParam; - std::string sAddress; - double dAllocation = 0.0; + SideStakeAlloc vSideStakeAlloc; + std::vector> raw_vSideStakeAlloc; double dSumAllocation = 0.0; - bool fEnableSideStaking = gArgs.GetBoolArg("-enablesidestaking"); - LogPrint(BCLog::LogFlags::MINER, "StakeMiner: fEnableSideStaking = %u", fEnableSideStaking); + // 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 side staking is enabled, 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 (fEnableSideStaking) + // 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()) { - if (gArgs.GetArgs("-sidestake").size()) + for (auto const& sSubParam : gArgs.GetArgs("-sidestake")) { - for (auto const& sSubParam : gArgs.GetArgs("-sidestake")) + std::vector vSubParam; + + ParseString(sSubParam, ',', vSubParam); + if (vSubParam.size() != 2) { - ParseString(sSubParam, ',', vSubParam); - if (vSubParam.size() != 2) - { - LogPrintf("WARN: StakeMiner: Incompletely SideStake Allocation specified. Skipping SideStake entry."); - vSubParam.clear(); - continue; - } + LogPrintf("WARN: %s: Incomplete SideStake Allocation specified. Skipping SideStake entry.", __func__); + continue; + } - sAddress = vSubParam[0]; + raw_vSideStakeAlloc.push_back(std::make_pair(vSubParam[0], vSubParam[1])); + } + } - CBitcoinAddress address(sAddress); - if (!address.IsValid()) - { - LogPrintf("WARN: StakeMiner: ignoring sidestake invalid address %s.", sAddress.c_str()); - vSubParam.clear(); - continue; - } + for (auto const& entry : raw_vSideStakeAlloc) + { + std::string sAddress; + double dAllocation = 0.0; - try - { - dAllocation = stof(vSubParam[1]) / 100.0; - } - catch(...) - { - LogPrintf("WARN: StakeMiner: Invalid allocation provided. Skipping allocation."); - vSubParam.clear(); - continue; - } + sAddress = entry.first; - if (dAllocation <= 0) - { - LogPrintf("WARN: StakeMiner: Negative or zero allocation provided. Skipping allocation."); - vSubParam.clear(); - continue; - } + CBitcoinAddress address(sAddress); + if (!address.IsValid()) + { + LogPrintf("WARN: %s: ignoring sidestake invalid address %s.", __func__, sAddress); + 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: StakeMiner: allocation percentage over 100\%, ending sidestake allocations."); - break; - } + try + { + dAllocation = stof(entry.second) / 100.0; + } + catch (std::exception& e) + { + LogPrintf("WARN: %s: Invalid allocation provided. Skipping allocation.", __func__); + continue; + } - vSideStakeAlloc.push_back(std::pair(sAddress, dAllocation)); - LogPrint(BCLog::LogFlags::MINER, "StakeMiner: SideStakeAlloc Address %s, Allocation %f", - sAddress.c_str(), dAllocation); + if (dAllocation <= 0) + { + LogPrintf("WARN: %s: Negative or zero allocation provided. Skipping allocation.", __func__); + continue; + } - vSubParam.clear(); - } + // 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\%, ending sidestake allocations.", __func__); + break; } - // 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: StakeMiner: enablesidestaking was set in config but nothing has been allocated for" - " distribution!"); + + vSideStakeAlloc.push_back(std::pair(sAddress, dAllocation)); + LogPrint(BCLog::LogFlags::MINER, "INFO: %s: SideStakeAlloc Address %s, Allocation %f", + __func__, sAddress, dAllocation); } - return fEnableSideStaking; + // 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!"); + + return vSideStakeAlloc; } // This function parses the config file for the directives for stake splitting. It is used @@ -1325,17 +1346,21 @@ void StakeMiner(CWallet *pwallet) int64_t nMinStakeSplitValue = 0; double dEfficiency = 0; int64_t nDesiredStakeOutputValue = 0; - SideStakeAlloc vSideStakeAlloc = {}; - - // nMinStakeSplitValue and dEfficiency are out parameters. - bool fEnableStakeSplit = GetStakeSplitStatusAndParams(nMinStakeSplitValue, dEfficiency, nDesiredStakeOutputValue); - - // vSideStakeAlloc is an out parameter. - bool fEnableSideStaking = GetSideStakingStatusAndAlloc(vSideStakeAlloc); + SideStakeAlloc vSideStakeAlloc; while (!fShutdown) { - //wait for next round + // nMinStakeSplitValue and dEfficiency are out parameters. + bool fEnableStakeSplit = GetStakeSplitStatusAndParams(nMinStakeSplitValue, dEfficiency, nDesiredStakeOutputValue); + + bool fEnableSideStaking = gArgs.GetBoolArg("-enablesidestaking"); + + LogPrint(BCLog::LogFlags::MINER, "StakeMiner: fEnableSideStaking = %u", fEnableSideStaking); + + // vSideStakeAlloc is an out parameter. + if (fEnableSideStaking) vSideStakeAlloc = GetSideStakingStatusAndAlloc(); + + // wait for next round MilliSleep(nMinerSleep); g_timer.InitTimer("miner", LogInstance().WillLogCategory(BCLog::LogFlags::MISC)); diff --git a/src/miner.h b/src/miner.h index 343920bea5..e3b238382f 100644 --- a/src/miner.h +++ b/src/miner.h @@ -25,7 +25,7 @@ std::optional GetLastStake(CWallet& wallet); 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); -bool GetSideStakingStatusAndAlloc(SideStakeAlloc& vSideStakeAlloc); +SideStakeAlloc GetSideStakingStatusAndAlloc(); bool GetStakeSplitStatusAndParams(int64_t& nMinStakeSplitValue, double& dEfficiency, int64_t& nDesiredStakeOutputValue); #endif // NOVACOIN_MINER_H diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 5deb0e517b..b29285e315 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -111,8 +111,9 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) // nMinStakeSplitValue, dEfficiency, and nDesiredStakeSplitValue are out parameters. bool fEnableStakeSplit = GetStakeSplitStatusAndParams(nMinStakeSplitValue, dEfficiency, nDesiredStakeSplitValue); - // vSideStakeAlloc is an out parameter. - bool fEnableSideStaking = GetSideStakingStatusAndAlloc(vSideStakeAlloc); + bool fEnableSideStaking = gArgs.GetBoolArg("-enablesidestaking"); + + vSideStakeAlloc = GetSideStakingStatusAndAlloc(); stakesplitting.pushKV("stake-splitting-enabled", fEnableStakeSplit); if (fEnableStakeSplit)