Skip to content

Commit

Permalink
Merged in finalize-mining-support (pull request #31)
Browse files Browse the repository at this point in the history
Finalize mining support

Approved-by: Cevap
  • Loading branch information
FornaxA authored and Cevap committed Mar 9, 2020
2 parents 01f32a5 + 14df1ea commit c2b308e
Show file tree
Hide file tree
Showing 17 changed files with 352 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down Expand Up @@ -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 \
Expand Down
14 changes: 12 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -2007,6 +2008,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)

// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
rewardManager = std::shared_ptr<CRewardManager>(new CRewardManager());
if (!CWallet::InitLoadWallet())
return false;
#else
Expand Down Expand Up @@ -2163,6 +2165,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
stakingManager = std::shared_ptr<CStakingManager>(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;
Expand All @@ -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

Expand Down
4 changes: 3 additions & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ std::unique_ptr<CBlockTemplate> 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())
Expand Down
6 changes: 5 additions & 1 deletion src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
7 changes: 6 additions & 1 deletion src/primitives/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "streams.h"
#include "tinyformat.h"
#include "utilstrencodings.h"
#include "versionbits.h"
#include "crypto/common.h"

uint256 CBlockHeader::GetHash() const
Expand All @@ -17,7 +18,11 @@ uint256 CBlockHeader::GetHash() const
std::vector<unsigned char> 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
Expand Down
2 changes: 1 addition & 1 deletion src/primitives/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
166 changes: 166 additions & 0 deletions src/reward-manager.cpp
Original file line number Diff line number Diff line change
@@ -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 <boost/thread.hpp>

std::shared_ptr<CRewardManager> 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<CBitcoinAddress, std::vector<COutput> > CRewardManager::AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue) {
std::vector<COutput> vCoins;
pwallet->AvailableCoins(vCoins, fConfirmed);

std::map<CBitcoinAddress, std::vector<COutput> > 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<CBitcoinAddress, std::vector<COutput> > 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<CBitcoinAddress, std::vector<COutput> >::iterator it = mapCoinsByAddress.begin(); it != mapCoinsByAddress.end(); it++) {
std::vector<COutput> 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<CRecipient> 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();
}
}
52 changes: 52 additions & 0 deletions src/reward-manager.h
Original file line number Diff line number Diff line change
@@ -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<CRewardManager> 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<CBitcoinAddress, std::vector<COutput> > AvailableCoinsByAddress(bool fConfirmed, CAmount maxCoinValue);
void AutoCombineRewards();

void DoMaintenance(CConnman& connman);
};

#endif // REWARD_MANAGER_H
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
23 changes: 22 additions & 1 deletion src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<CTxOut> 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
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion src/tokens/rpctokenwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
Loading

0 comments on commit c2b308e

Please sign in to comment.