PIVX Core  5.6.99
P2P Digital Currency
miner.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Copyright (c) 2014-2015 The Dash developers
4 // Copyright (c) 2011-2013 The PPCoin developers
5 // Copyright (c) 2013-2014 The NovaCoin Developers
6 // Copyright (c) 2014-2018 The BlackCoin Developers
7 // Copyright (c) 2015-2021 The PIVX Core developers
8 // Distributed under the MIT/X11 software license, see the accompanying
9 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
10 
11 #include "miner.h"
12 
13 #include "amount.h"
14 #include "blockassembler.h"
15 #include "consensus/params.h"
16 #include "masternode-sync.h"
17 #include "net.h"
18 #include "policy/feerate.h"
19 #include "primitives/block.h"
20 #include "primitives/transaction.h"
21 #include "timedata.h"
22 #include "util/blockstatecatcher.h"
23 #include "util/system.h"
24 #include "utilmoneystr.h"
25 #ifdef ENABLE_WALLET
26 #include "wallet/wallet.h"
27 #endif
28 #include "invalid.h"
29 #include "policy/policy.h"
30 
31 #include <boost/thread.hpp>
32 
33 #ifdef ENABLE_WALLET
35 //
36 // Internal miner
37 //
38 double dHashesPerSec = 0.0;
39 int64_t nHPSTimerStart = 0;
40 
41 std::unique_ptr<CBlockTemplate> CreateNewBlockWithKey(std::unique_ptr<CReserveKey>& reservekey, CWallet* pwallet)
42 {
43  CPubKey pubkey;
44  if (!reservekey->GetReservedKey(pubkey)) return nullptr;
45  return CreateNewBlockWithScript(GetScriptForDestination(pubkey.GetID()), pwallet);
46 }
47 
48 std::unique_ptr<CBlockTemplate> CreateNewBlockWithScript(const CScript& coinbaseScript, CWallet* pwallet)
49 {
50  const int nHeightNext = chainActive.Tip()->nHeight + 1;
51 
52  // If we're building a late PoW block, don't continue
53  // PoS blocks are built directly with CreateNewBlock
54  if (Params().GetConsensus().NetworkUpgradeActive(nHeightNext, Consensus::UPGRADE_POS)) {
55  LogPrintf("%s: Aborting PoW block creation during PoS phase\n", __func__);
56  // sleep 1/2 a block time so we don't go into a tight loop.
57  MilliSleep((Params().GetConsensus().nTargetSpacing * 1000) >> 1);
58  return nullptr;
59  }
60 
61  return BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(coinbaseScript, pwallet, false);
62 }
63 
64 bool ProcessBlockFound(const std::shared_ptr<const CBlock>& pblock, CWallet& wallet, std::unique_ptr<CReserveKey>& reservekey)
65 {
66  LogPrintf("%s\n", pblock->ToString());
67  LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue));
68 
69  // Found a solution
70  {
72  if (pblock->hashPrevBlock != g_best_block)
73  return error("PIVXMiner : generated block is stale");
74  }
75 
76  // Remove key from key pool
77  if (reservekey)
78  reservekey->KeepKey();
79 
80  // Process this block the same as if we had received it from another node
81  BlockStateCatcherWrapper sc(pblock->GetHash());
82  sc.registerEvent();
83  bool res = ProcessNewBlock(pblock, nullptr);
84  if (!res || sc.get().stateErrorFound()) {
85  return error("PIVXMiner : ProcessNewBlock, block not accepted");
86  }
87 
88  g_connman->ForEachNode([&pblock](CNode* node)
89  {
90  node->PushInventory(CInv(MSG_BLOCK, pblock->GetHash()));
91  });
92 
93  return true;
94 }
95 
96 bool fGenerateBitcoins = false;
97 bool fStakeableCoins = false;
98 
99 void CheckForCoins(CWallet* pwallet, std::vector<CStakeableOutput>* availableCoins)
100 {
101  if (!pwallet || !pwallet->pStakerStatus)
102  return;
103 
104  // control the amount of times the client will check for mintable coins (every block)
105  {
107  if (g_best_block == pwallet->pStakerStatus->GetLastHash())
108  return;
109  }
110  fStakeableCoins = pwallet->StakeableCoins(availableCoins);
111 }
112 
113 void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)
114 {
115  LogPrintf("PIVXMiner started\n");
117  util::ThreadRename("pivx-miner");
118  const Consensus::Params& consensus = Params().GetConsensus();
119  const int64_t nSpacingMillis = consensus.nTargetSpacing * 1000;
120 
121  // Each thread has its own key and counter
122  std::unique_ptr<CReserveKey> pReservekey = fProofOfStake ? nullptr : std::make_unique<CReserveKey>(pwallet);
123 
124  // Available UTXO set
125  std::vector<CStakeableOutput> availableCoins;
126  unsigned int nExtraNonce = 0;
127 
128  while (fGenerateBitcoins || fProofOfStake) {
129  CBlockIndex* pindexPrev = GetChainTip();
130  if (!pindexPrev) {
131  MilliSleep(nSpacingMillis); // sleep a block
132  continue;
133  }
134  if (fProofOfStake) {
135  if (!consensus.NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_POS)) {
136  // The last PoW block hasn't even been mined yet.
137  MilliSleep(nSpacingMillis); // sleep a block
138  continue;
139  }
140 
141  // update fStakeableCoins
142  CheckForCoins(pwallet, &availableCoins);
143 
144  while ((g_connman && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && Params().MiningRequiresPeers())
145  || pwallet->IsLocked() || !fStakeableCoins || masternodeSync.NotCompleted()) {
146  MilliSleep(5000);
147  // Do another check here to ensure fStakeableCoins is updated
148  if (!fStakeableCoins) CheckForCoins(pwallet, &availableCoins);
149  }
150 
151  //search our map of hashed blocks, see if bestblock has been hashed yet
152  if (pwallet->pStakerStatus &&
153  pwallet->pStakerStatus->GetLastHash() == pindexPrev->GetBlockHash() &&
154  pwallet->pStakerStatus->GetLastTime() >= GetCurrentTimeSlot()) {
155  MilliSleep(2000);
156  continue;
157  }
158 
159  } else if (pindexPrev->nHeight > 6 && consensus.NetworkUpgradeActive(pindexPrev->nHeight - 6, Consensus::UPGRADE_POS)) {
160  // Late PoW: run for a little while longer, just in case there is a rewind on the chain.
161  LogPrintf("%s: Exiting PoW Mining Thread at height: %d\n", __func__, pindexPrev->nHeight);
162  return;
163  }
164 
165  //
166  // Create new block
167  //
168  unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
169 
170  std::unique_ptr<CBlockTemplate> pblocktemplate((fProofOfStake ?
171  BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins) :
172  CreateNewBlockWithKey(pReservekey, pwallet)));
173  if (!pblocktemplate) continue;
174  std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);
175 
176  // POS - block found: process it
177  if (fProofOfStake) {
178  LogPrintf("%s : proof-of-stake block was signed %s \n", __func__, pblock->GetHash().ToString().c_str());
180  if (!ProcessBlockFound(pblock, *pwallet, pReservekey)) {
181  LogPrintf("%s: New block orphaned\n", __func__);
182  continue;
183  }
185  continue;
186  }
187 
188  // POW - miner main
189  IncrementExtraNonce(pblock, pindexPrev->nHeight + 1, nExtraNonce);
190 
191  LogPrintf("Running PIVXMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
192  ::GetSerializeSize(*pblock, PROTOCOL_VERSION));
193 
194  //
195  // Search
196  //
197  int64_t nStart = GetTime();
198  arith_uint256& hashTarget = arith_uint256().SetCompact(pblock->nBits);
199  while (true) {
200  unsigned int nHashesDone = 0;
201 
202  arith_uint256 hash;
203  while (true) {
204  hash = UintToArith256(pblock->GetHash());
205  if (hash <= hashTarget) {
206  // Found a solution
208  LogPrintf("%s:\n", __func__);
209  LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
210  ProcessBlockFound(pblock, *pwallet, pReservekey);
212 
213  // In regression test mode, stop mining after a block is found. This
214  // allows developers to controllably generate a block on demand.
215  if (Params().IsRegTestNet())
216  throw boost::thread_interrupted();
217 
218  break;
219  }
220  pblock->nNonce += 1;
221  nHashesDone += 1;
222  if ((pblock->nNonce & 0xFF) == 0)
223  break;
224  }
225 
226  // Meter hashes/sec
227  static int64_t nHashCounter;
228  if (nHPSTimerStart == 0) {
230  nHashCounter = 0;
231  } else
232  nHashCounter += nHashesDone;
233  if (GetTimeMillis() - nHPSTimerStart > 4000) {
234  static RecursiveMutex cs;
235  {
236  LOCK(cs);
237  if (GetTimeMillis() - nHPSTimerStart > 4000) {
238  dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
240  nHashCounter = 0;
241  static int64_t nLogTime;
242  if (GetTime() - nLogTime > 30 * 60) {
243  nLogTime = GetTime();
244  LogPrintf("hashmeter %6.0f khash/s\n", dHashesPerSec / 1000.0);
245  }
246  }
247  }
248  }
249 
250  // Check for stop or if block needs to be rebuilt
251  boost::this_thread::interruption_point();
252  if ( (g_connman && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && Params().MiningRequiresPeers()) || // Regtest mode doesn't require peers
253  (pblock->nNonce >= 0xffff0000) ||
254  (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) ||
255  (pindexPrev != chainActive.Tip())
256  ) break;
257 
258  // Update nTime every few seconds
259  UpdateTime(pblock.get(), consensus, pindexPrev);
260  if (Params().GetConsensus().fPowAllowMinDifficultyBlocks) {
261  // Changing pblock->nTime can change work required on testnet:
262  hashTarget.SetCompact(pblock->nBits);
263  }
264 
265  }
266  }
267 }
268 
269 void static ThreadBitcoinMiner(void* parg)
270 {
271  boost::this_thread::interruption_point();
272  CWallet* pwallet = (CWallet*)parg;
273  try {
274  BitcoinMiner(pwallet, false);
275  boost::this_thread::interruption_point();
276  } catch (const std::exception& e) {
277  LogPrintf("PIVXMiner exception\n");
278  } catch (...) {
279  LogPrintf("PIVXMiner exception\n");
280  }
281 
282  LogPrintf("PIVXMiner exiting\n");
283 }
284 
285 void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
286 {
287  static boost::thread_group* minerThreads = nullptr;
288  fGenerateBitcoins = fGenerate;
289 
290  if (minerThreads != nullptr) {
291  minerThreads->interrupt_all();
292  delete minerThreads;
293  minerThreads = nullptr;
294  }
295 
296  if (nThreads == 0 || !fGenerate)
297  return;
298 
299  minerThreads = new boost::thread_group();
300  for (int i = 0; i < nThreads; i++)
301  minerThreads->create_thread(std::bind(&ThreadBitcoinMiner, pwallet));
302 }
303 
304 void ThreadStakeMinter()
305 {
306  boost::this_thread::interruption_point();
307  LogPrintf("ThreadStakeMinter started. Using wallet-0\n");
308  CWallet* pwallet = vpwallets[0];
309  try {
310  BitcoinMiner(pwallet, true);
311  boost::this_thread::interruption_point();
312  } catch (const std::exception& e) {
313  LogPrintf("ThreadStakeMinter() exception \n");
314  } catch (...) {
315  LogPrintf("ThreadStakeMinter() error \n");
316  }
317  LogPrintf("ThreadStakeMinter exiting,\n");
318 }
319 
320 #endif // ENABLE_WALLET
arith_uint256 UintToArith256(const uint256 &a)
void IncrementExtraNonce(std::shared_ptr< CBlock > &pblock, int nHeight, unsigned int &nExtraNonce)
int64_t UpdateTime(CBlockHeader *pblock, const Consensus::Params &consensusParams, const CBlockIndex *pindexPrev)
const CChainParams & Params()
Return the currently selected parameters.
Generate a new block.
std::unique_ptr< CBlockTemplate > CreateNewBlock(const CScript &scriptPubKeyIn, CWallet *pwallet=nullptr, bool fProofOfStake=false, std::vector< CStakeableOutput > *availableCoins=nullptr, bool fNoMempoolTx=false, bool fTestValidity=true, CBlockIndex *prevBlock=nullptr, bool stopPoSOnNewBlock=true, bool fIncludeQfc=true)
Construct a new block template with coinbase to scriptPubKeyIn.
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
uint256 GetBlockHash() const
Definition: chain.h:215
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
CBlockIndex * Tip(bool fProofOfStake=false) const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:405
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
@ CONNECTIONS_ALL
Definition: net.h:152
bool IsLocked() const
Definition: crypter.cpp:148
inv message data
Definition: protocol.h:466
Information about a peer.
Definition: net.h:669
void PushInventory(const CInv &inv)
Definition: net.h:914
An encapsulated public key.
Definition: pubkey.h:44
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
int64_t GetLastTime() const
Definition: wallet.h:199
uint256 GetLastHash() const
Definition: wallet.h:195
unsigned int GetTransactionsUpdated() const
Definition: txmempool.cpp:351
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:577
CStakerStatus * pStakerStatus
Definition: wallet.h:737
256-bit unsigned big integer.
arith_uint256 & SetCompact(uint32_t nCompact, bool *pfNegative=nullptr, bool *pfOverflow=nullptr)
The "compact" format is a representation of a whole number N using an unsigned 32bit number similar t...
std::string GetHex() const
#define THREAD_PRIORITY_LOWEST
Definition: compat.h:87
#define THREAD_PRIORITY_NORMAL
Definition: compat.h:89
bool StakeableCoins(std::vector< CStakeableOutput > *pCoins=nullptr)
Available coins (staking)
Definition: wallet.cpp:2709
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
CMasternodeSync masternodeSync
double dHashesPerSec
int64_t nHPSTimerStart
@ UPGRADE_POS
Definition: params.h:28
void ThreadRename(std::string &&)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
Definition: threadnames.cpp:62
@ MSG_BLOCK
Definition: protocol.h:437
unsigned int GetSerializeSize(const std::array< T, N > &item)
array
Definition: serialize.h:847
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
Parameters that influence chain consensus.
Definition: params.h:171
int64_t nTargetSpacing
Definition: params.h:193
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
#define WAIT_LOCK(cs, name)
Definition: sync.h:225
void SetThreadPriority(int nPriority)
Definition: system.cpp:1082
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
int64_t GetCurrentTimeSlot()
Definition: timedata.cpp:106
bool NetworkUpgradeActive(int nHeight, const Consensus::Params &params, Consensus::UpgradeIndex idx)
Returns true if the given network upgrade is active as of the given block height.
Definition: upgrades.cpp:107
std::string FormatMoney(const CAmount &n, bool fPlus)
Money parsing/formatting utilities.
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: utiltime.cpp:61
void MilliSleep(int64_t n)
Definition: utiltime.cpp:82
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27
CTxMemPool mempool(::minRelayTxFee)
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &pblock, const FlatFilePos *dbp)
Process an incoming block.
Mutex g_best_block_mutex
Definition: validation.cpp:88
CBlockIndex * GetChainTip()
Return a reliable pointer (in mapBlockIndex) to the chain's tip index.
Definition: validation.cpp:194
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:84
uint256 g_best_block
Definition: validation.cpp:90
std::vector< CWalletRef > vpwallets
Definition: wallet.cpp:33