diff --git a/src/Makefile.am b/src/Makefile.am index c669e933411df..8e0e53422ac4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -229,6 +229,7 @@ BITCOIN_CORE_H = \ random.h \ reverse_iterator.h \ reverselock.h \ + reward-manager.h \ rpc/blockchain.h \ rpc/client.h \ rpc/mining.h \ @@ -420,6 +421,7 @@ libion_wallet_a_SOURCES = \ pos/staking-manager.cpp \ privatesend/privatesend-client.cpp \ privatesend/privatesend-util.cpp \ + reward-manager.cpp \ tokens/rpctokenwallet.cpp \ tokens/tokengroupwallet.cpp \ transactionrecord.cpp \ diff --git a/src/init.cpp b/src/init.cpp index 94d058777f30a..5d44f5756df9c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -32,6 +32,7 @@ #include "policy/policy.h" #ifdef ENABLE_WALLET #include "pos/staking-manager.h" +#include "reward-manager.h" #endif #include "rpc/server.h" #include "rpc/register.h" @@ -2007,6 +2008,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET + rewardManager = std::shared_ptr(new CRewardManager()); if (!CWallet::InitLoadWallet()) return false; #else @@ -2163,6 +2165,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) stakingManager = std::shared_ptr(new CStakingManager(vpwallets[0])); stakingManager->fEnableStaking = gArgs.GetBoolArg("-staking", !fLiteMode); stakingManager->fEnableIONStaking = gArgs.GetBoolArg("-staking", true); + + rewardManager->BindWallet(vpwallets[0]); + rewardManager->fEnableRewardManager = true; } if (Params().NetworkIDString() == CBaseChainParams::REGTEST) { stakingManager->fEnableStaking = false; @@ -2176,8 +2181,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) stakingManager->nReserveBalance = n; } - if (!fLiteMode && stakingManager->fEnableStaking) { - scheduler.scheduleEvery(boost::bind(&CStakingManager::DoMaintenance, boost::ref(stakingManager), boost::ref(*g_connman)), 5 * 1000); + if (!fLiteMode) { + if (stakingManager->fEnableStaking) { + scheduler.scheduleEvery(boost::bind(&CStakingManager::DoMaintenance, boost::ref(stakingManager), boost::ref(*g_connman)), 5 * 1000); + } + if (rewardManager->fEnableRewardManager) { + scheduler.scheduleEvery(boost::bind(&CRewardManager::DoMaintenance, boost::ref(rewardManager), boost::ref(*g_connman)), 5 * 60 * 1000); + } } #endif // ENABLE_WALLET diff --git a/src/miner.cpp b/src/miner.cpp index 5f8ed32417389..e94de57401246 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -184,7 +184,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc bool fDIP0003Active_context = nHeight >= chainparams.GetConsensus().DIP0003Height; bool fDIP0008Active_context = VersionBitsState(chainActive.Tip(), chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0008, versionbitscache) == THRESHOLD_ACTIVE; - pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus(), fPos, chainparams.BIP9CheckMasternodesUpgraded()); + pblock->nVersion = nHeight >= chainparams.GetConsensus().POSPOWStartHeight ? + ComputeBlockVersion(pindexPrev, chainparams.GetConsensus(), fPos, chainparams.BIP9CheckMasternodesUpgraded()) + : VERSIONBITS_LAST_OLD_BLOCK_VERSION; // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) diff --git a/src/pow.cpp b/src/pow.cpp index 32c5acbe0259b..9822f2b782ae2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -39,7 +39,11 @@ unsigned int static HybridPoWDarkGravityWave(const CBlockIndex* pindexLastIn, co } if (params.fPowAllowMinDifficultyBlocks) { - int64_t nPrevBlockTime = GetHybridPrevIndex(pindexLastIn, false, params.POSPOWStartHeight)->GetBlockTime(); + const CBlockIndex* pindexPrev = GetHybridPrevIndex(pindexLast, false, params.POSPOWStartHeight); + if (pindexPrev == nullptr) { + return bnPowLimit.GetCompact(); + } + int64_t nPrevBlockTime = pindexPrev->GetBlockTime(); // recent block is more than 2 hours old if (pindexLast->GetBlockTime() > nPrevBlockTime + 2 * 60 * 60) { return bnPowLimit.GetCompact(); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 4dfb3d2fa4e56..a38c2f389f9f6 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -9,6 +9,7 @@ #include "streams.h" #include "tinyformat.h" #include "utilstrencodings.h" +#include "versionbits.h" #include "crypto/common.h" uint256 CBlockHeader::GetHash() const @@ -17,7 +18,11 @@ uint256 CBlockHeader::GetHash() const std::vector vch(80); CVectorWriter ss(SER_NETWORK, PROTOCOL_VERSION, vch, 0); ss << *this; - return Hash((const char *)vch.data(), (const char *)vch.data() + vch.size()); + if ((nVersion & BLOCKTYPEBITS_MASK) == BlockTypeBits::BLOCKTYPE_MINING) { + return HashX11((const char *)vch.data(), (const char *)vch.data() + vch.size()); + } else { + return Hash((const char *)vch.data(), (const char *)vch.data() + vch.size()); + } } std::string CBlock::ToString() const diff --git a/src/primitives/block.h b/src/primitives/block.h index 60eabe53317ce..4b63fa467cfdf 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -45,7 +45,7 @@ class CBlockHeader READWRITE(nBits); READWRITE(nNonce); //zerocoin active, header changes to include accumulator checksum - if(nVersion > 7) + if(nVersion > 7 && nVersion <= 11) READWRITE(nAccumulatorCheckpoint); } diff --git a/src/reward-manager.cpp b/src/reward-manager.cpp new file mode 100644 index 0000000000000..895c55d5005c4 --- /dev/null +++ b/src/reward-manager.cpp @@ -0,0 +1,166 @@ +// Copyright (c) 2014-2020 The Ion Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "reward-manager.h" + +#include "init.h" +#include "masternode/masternode-sync.h" +#include "policy/policy.h" +#include "validation.h" +#include "wallet/wallet.h" + +// fix windows build +#include + +std::shared_ptr rewardManager; + +CRewardManager::CRewardManager() : + fEnableRewardManager(false), fEnableAutoCombineRewards(false), nAutoCombineThreshold(0) { +} + +bool CRewardManager::IsReady() { + if (!fEnableRewardManager) return false; + + if (pwallet == nullptr || pwallet->IsLocked()) { + return false; + } + bool fHaveConnections = !g_connman ? false : g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) > 0; + if (!fHaveConnections || !masternodeSync.IsSynced()) { + return false; + } + const CBlockIndex* tip = chainActive.Tip(); + if (tip == nullptr || tip->nTime < (GetAdjustedTime() - 300)) { + return false; + } + return true; +} + +bool CRewardManager::IsCombining() +{ + return IsReady() && IsAutoCombineEnabled(); +} + +void CRewardManager::AutoCombineSettings(bool fEnable, CAmount nAutoCombineThresholdIn) { + LOCK(cs); + fEnableAutoCombineRewards = fEnable; + nAutoCombineThreshold = nAutoCombineThresholdIn; +} + +// TODO: replace with pwallet->FilterCoins() +std::map > CRewardManager::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue) { + std::vector vCoins; + pwallet->AvailableCoins(vCoins, fConfirmed); + + std::map > mapCoins; + for (COutput out : vCoins) { + if (maxCoinValue > 0 && out.tx->tx->vout[out.i].nValue > maxCoinValue) + continue; + + CTxDestination address; + if (!ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address)) + continue; + + mapCoins[CBitcoinAddress(address)].push_back(out); + } + + return mapCoins; +} + +void CRewardManager::AutoCombineRewards() { + LOCK2(cs_main, pwallet->cs_wallet); + + std::map > mapCoinsByAddress = AvailableCoinsByAddress(true, nAutoCombineThreshold * COIN); + + //coins are sectioned by address. This combination code only wants to combine inputs that belong to the same address + for (std::map >::iterator it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) { + std::vector vCoins, vRewardCoins; + bool maxSize = false; + vCoins = it->second; + + // We don't want the tx to be refused for being too large + // we use 50 bytes as a base tx size (2 output: 2*34 + overhead: 10 -> 90 to be certain) + unsigned int txSizeEstimate = 90; + + //find masternode rewards that need to be combined + CCoinControl coinControl; + CAmount nTotalRewardsValue = 0; + for (const COutput& out : vCoins) { + if (!out.fSpendable) + continue; + + COutPoint outpt(out.tx->GetHash(), out.i); + coinControl.Select(outpt); + vRewardCoins.push_back(out); + nTotalRewardsValue += out.GetValue(); + + // Combine to the threshold and not way above + if (nTotalRewardsValue > nAutoCombineThreshold * COIN) + break; + + // Around 180 bytes per input. We use 190 to be certain + txSizeEstimate += 190; + if (txSizeEstimate >= MAX_STANDARD_TX_SIZE - 200) { + maxSize = true; + break; + } + } + + //if no inputs found then return + if (!coinControl.HasSelected()) + continue; + + //we cannot combine one coin with itself + if (vRewardCoins.size() <= 1) + continue; + + std::vector vecSend; + int nChangePosRet = -1; + CScript scriptPubKey = GetScriptForDestination(it->first.Get()); + // 10% safety margin to avoid "Insufficient funds" errors + CRecipient recipient = {scriptPubKey, nTotalRewardsValue - (nTotalRewardsValue / 10), false}; + vecSend.push_back(recipient); + + //Send change to same address + CTxDestination destMyAddress; + if (!ExtractDestination(scriptPubKey, destMyAddress)) { + LogPrintf("AutoCombineDust: failed to extract destination\n"); + continue; + } + coinControl.destChange = destMyAddress; + + // Create the transaction and commit it to the network + CWalletTx wtx; + CReserveKey keyChange(pwallet); // this change address does not end up being used, because change is returned with coin control switch + std::string strErr; + CAmount nFeeRet = 0; + + if (!pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRet, nChangePosRet, strErr, coinControl)) { + LogPrintf("AutoCombineDust createtransaction failed, reason: %s\n", strErr); + continue; + } + + //we don't combine below the threshold unless the fees are 0 to avoid paying fees over fees over fees + if (!maxSize && nTotalRewardsValue < nAutoCombineThreshold * COIN && nFeeRet > 0) + continue; + + CValidationState state; + if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) { + LogPrintf("AutoCombineDust transaction commit failed\n"); + continue; + } + + LogPrintf("AutoCombineDust sent transaction\n"); + } +} + +void CRewardManager::DoMaintenance(CConnman& connman) { + if (!IsReady()) { + MilliSleep(5 * 60 * 1000); // Wait 5 minutes + return; + } + + if (IsAutoCombineEnabled()) { + AutoCombineRewards(); + } +} diff --git a/src/reward-manager.h b/src/reward-manager.h new file mode 100644 index 0000000000000..6180685f7a6d3 --- /dev/null +++ b/src/reward-manager.h @@ -0,0 +1,52 @@ +// Copyright (c) 2020 The Ion Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef REWARD_MANAGER_H +#define REWARD_MANAGER_H + +#include "amount.h" +#include "base58.h" +#include "sync.h" + +class CConnman; +class CRewardManager; +class COutput; +class CWallet; + +extern std::shared_ptr rewardManager; + +class CRewardManager +{ +public: + CCriticalSection cs; + +private: + CWallet* pwallet = nullptr; + +public: + CRewardManager(); + + void BindWallet(CWallet * const pwalletIn) { + pwallet = pwalletIn; + } + + bool fEnableRewardManager; + + bool fEnableAutoCombineRewards; + CAmount nAutoCombineThreshold; + + bool IsReady(); + bool IsCombining(); + + bool IsAutoCombineEnabled() { return fEnableAutoCombineRewards; }; + CAmount GetAutoCombineThreshold() { return nAutoCombineThreshold; }; + void AutoCombineSettings(bool fEnable, CAmount nAutoCombineThresholdIn = 0); + + std::map > AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue); + void AutoCombineRewards(); + + void DoMaintenance(CConnman& connman); +}; + +#endif // REWARD_MANAGER_H diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b2a919303cb8c..6cb390ce83eea 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -176,6 +176,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getspecialtxes", 4, "verbosity" }, { "disconnectnode", 1, "nodeid" }, { "setstakesplitthreshold", 0, "value" }, + { "autocombinerewards", 0, "enable" }, + { "autocombinerewards", 1, "threshold" }, // Echo with conversion (For testing only) { "echojson", 0, "arg0" }, { "echojson", 1, "arg1" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 39169134ac232..62942a675b30d 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -351,6 +351,14 @@ UniValue getblocktemplate(const JSONRPCRequest& request) " },\n" " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" + " \"minerrewards\" : [ (array) contents of a single transaction to the miner\n" + " {\n" + " \"amount\": n, (numeric) amount \n" + " \"tokenid\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" + " \"tokenamount\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" + " }\n" + " ,...\n" + " ],\n" " \"target\" : \"xxxx\", (string) The hash target\n" " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" @@ -471,7 +479,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) // Get expected MN/superblock payees. The call to GetBlockTxOuts might fail on regtest/devnet or when // testnet is reset. This is fine and we ignore failure (blocks will be accepted) std::vector voutMasternodePayments; - CBlockReward blockReward; + CBlockReward blockReward(chainActive.Height() + 1, 0, false, Params().GetConsensus()); mnpayments.GetBlockTxOuts(chainActive.Height() + 1, blockReward, voutMasternodePayments); // next bock is a superblock and we need governance info to correctly construct it @@ -665,6 +673,19 @@ UniValue getblocktemplate(const JSONRPCRequest& request) result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->GetValueOut())); + + UniValue minerRewardObj(UniValue::VARR); + CReward minerReward = blockReward.GetCoinbaseReward(); + for (const auto& minerTokenReward : minerReward.tokenAmounts) { + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("amount", 1)); + obj.push_back(Pair("tokenid", HexStr(minerTokenReward.first.bytes()))); + obj.push_back(Pair("tokenamount", minerTokenReward.second)); + minerRewardObj.push_back(obj); + } + + result.push_back(Pair("minerrewards", minerRewardObj)); + result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); diff --git a/src/tokens/rpctokenwallet.cpp b/src/tokens/rpctokenwallet.cpp index 84f5ffec3d153..bfef46cf7d8fe 100644 --- a/src/tokens/rpctokenwallet.cpp +++ b/src/tokens/rpctokenwallet.cpp @@ -1433,7 +1433,7 @@ extern UniValue droptokenauthorities(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMS, "Invalid parameter: wrong vout nr"); } - pwallet->AvailableCoins(availableCoins, true, nullptr, 0); + pwallet->AvailableCoins(availableCoins, true, nullptr, 0, MAX_MONEY, MAX_MONEY, 0, 0, 9999999, true); if (availableCoins.empty()) { throw JSONRPCError(RPC_INVALID_PARAMS, "Invalid parameter: provided output is not available"); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bbedeae325cf4..aeb04cd860bd9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -19,6 +19,7 @@ #include "pos/staker.h" #include "pos/staking-manager.h" #include "privatesend/privatesend-client.h" +#include "reward-manager.h" #include "rpc/mining.h" #include "rpc/server.h" #include "timedata.h" @@ -3276,8 +3277,6 @@ UniValue setstakesplitthreshold(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); - const UniValue &stakeSplitThreshold = request.params[0]; - uint64_t nStakeSplitThreshold = request.params[0].get_int64(); if (nStakeSplitThreshold > 999999) @@ -3298,6 +3297,60 @@ UniValue setstakesplitthreshold(const JSONRPCRequest& request) return result; } +UniValue autocombinerewards(const JSONRPCRequest& request) +{ + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + bool fEnable; + size_t nParamsSize = request.params.size(); + if (nParamsSize >= 1) + fEnable = request.params[0].get_bool(); + + if (request.fHelp || nParamsSize < 1 || (!fEnable && nParamsSize > 1) || nParamsSize > 2) + throw std::runtime_error( + "autocombinerewards enable ( threshold )\n" + "\nWallet will automatically monitor for any coins with value below the threshold amount, and combine them if they reside with the same ION address\n" + "When autocombinerewards runs it will create a transaction, and therefore will be subject to transaction fees.\n" + + "\nArguments:\n" + "1. enable (boolean, required) Enable auto combine (true) or disable (false)\n" + "2. threshold (numeric, optional) Threshold amount (default: 0)\n" + + "\nExamples:\n" + + HelpExampleCli("autocombinerewards", "true 500") + HelpExampleRpc("autocombinerewards", "true 500")); + + EnsureWalletIsUnlocked(pwallet); + + CAmount nThreshold = 0; + + if (fEnable) { + nThreshold = request.params[1].get_int64(); + if (nThreshold < 0) + throw std::runtime_error("Value out of range, minimum allowed is 0"); + } + + CWalletDB walletdb(pwallet->GetDBHandle()); + LOCK(pwallet->cs_wallet); + + UniValue result(UniValue::VOBJ); + if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) { + throw std::runtime_error("Changed settings in wallet but failed to save to database\n"); + } + + rewardManager->AutoCombineSettings(fEnable, nThreshold); + + if (!walletdb.WriteAutoCombineSettings(fEnable, nThreshold)) + throw std::runtime_error("Changed settings in wallet but failed to save to database\n"); + + result.push_back(Pair("threshold", int(rewardManager->GetAutoCombineThreshold()))); + result.push_back(Pair("enabled", rewardManager->IsAutoCombineEnabled())); + + return result; +} + #if ENABLE_MINER UniValue generate(const JSONRPCRequest& request) { @@ -3473,6 +3526,8 @@ static const CRPCCommand commands[] = { "wallet", "importelectrumwallet", &importelectrumwallet, true, {"filename", "index"} }, { "wallet", "getstakingstatus", &getstakingstatus, false, {} }, + { "wallet", "setstakesplitthreshold", &setstakesplitthreshold, true, {"value"} }, + { "wallet", "autocombinerewards", &autocombinerewards, false, {"enable", "threshold"} }, }; void RegisterWalletRPCCommands(CRPCTable &t) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a270a8747de06..7f225dedaa2ca 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2978,7 +2978,7 @@ unsigned int CWallet::FilterCoins(std::vector &vCoins, return ret; } -void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth) const +void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t &nMaximumCount, const int &nMinDepth, const int &nMaxDepth, const bool includeGrouped) const { vCoins.clear(); CoinType nCoinType = coinControl ? coinControl->nCoinType : CoinType::ALL_COINS; @@ -2994,7 +2994,7 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const if (!CheckFinalTx(*pcoin)) continue; - if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) + if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -3014,6 +3014,9 @@ void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const continue; for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) { + if (!includeGrouped && IsOutputGrouped(pcoin->tx->vout[i])) + continue; + bool found = false; if(nCoinType == CoinType::ONLY_DENOMINATED) { found = CPrivateSend::IsDenominatedAmount(pcoin->tx->vout[i].nValue); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 41649da866ace..8d09889c370d7 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -938,7 +938,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface /** * populate vCoins with vector of available COutputs. */ - void AvailableCoins(std::vector& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999) const; + void AvailableCoins(std::vector& vCoins, bool fOnlySafe=true, const CCoinControl *coinControl = nullptr, const CAmount& nMinimumAmount = 1, const CAmount& nMaximumAmount = MAX_MONEY, const CAmount& nMinimumSumAmount = MAX_MONEY, const uint64_t& nMaximumCount = 0, const int& nMinDepth = 0, const int& nMaxDepth = 9999999, const bool fIncludeGrouped = false) const; /** * populate vCoins with vector of available COutputs, filtered by the passed lambda function. diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f0ddd13259883..d8ff297079103 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -11,6 +11,7 @@ #include "consensus/validation.h" #include "fs.h" #include "protocol.h" +#include "reward-manager.h" #include "serialize.h" #include "sync.h" #include "util.h" @@ -162,6 +163,14 @@ bool CWalletDB::WriteStakeSplitThreshold(uint64_t nStakeSplitThreshold) return WriteIC(std::string("stakeSplitThreshold"), nStakeSplitThreshold); } +bool CWalletDB::WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold) +{ + std::pair pSettings; + pSettings.first = fEnable; + pSettings.second = nCombineThreshold; + return WriteIC(std::string("autocombinesettings"), pSettings); +} + bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account) { account.SetNull(); @@ -546,6 +555,12 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { ssValue >> pwallet->nStakeSplitThreshold; } + else if (strType == "autocombinesettings") + { + std::pair pSettings; + ssValue >> pSettings; + rewardManager->AutoCombineSettings(pSettings.first, pSettings.second); + } } catch (...) { return false; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 8f6c9c2ec5892..dbda2b1ce93ea 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -155,6 +155,7 @@ class CWalletDB bool WriteMinVersion(int nVersion); bool WriteStakeSplitThreshold(uint64_t nStakeSplitThreshold); + bool WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold); /// This writes directly to the database, and will not update the CWallet's cached accounting entries! /// Use wallet.AddAccountingEntry instead, to write *and* update its caches. diff --git a/src/xion/accumulators.cpp b/src/xion/accumulators.cpp index 01885be9a819d..57a3547d3ea3e 100644 --- a/src/xion/accumulators.cpp +++ b/src/xion/accumulators.cpp @@ -321,7 +321,7 @@ bool ValidateAccumulatorCheckpoint(const CBlock& block, CBlockIndex* pindex, Acc //V1 accumulators are completely phased out by the time this code hits the public and begins generating new checkpoints //It is VERY IMPORTANT that when this is being run and height < v2_start, then xION need to be disabled at the same time!! bool fVerifyingBlocks = false; - if (pindex->nHeight < Params().GetConsensus().nBlockZerocoinV2 || fVerifyingBlocks) + if (pindex->nHeight < Params().GetConsensus().nBlockZerocoinV2 || pindex->nHeight >= Params().GetConsensus().IIP0006Height || fVerifyingBlocks) return true; if (pindex->nHeight % 10 == 0) {