Line data Source code
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
34 : //////////////////////////////////////////////////////////////////////////////
35 : //
36 : // Internal miner
37 : //
38 : double dHashesPerSec = 0.0;
39 : int64_t nHPSTimerStart = 0;
40 :
41 0 : std::unique_ptr<CBlockTemplate> CreateNewBlockWithKey(std::unique_ptr<CReserveKey>& reservekey, CWallet* pwallet)
42 : {
43 0 : CPubKey pubkey;
44 0 : if (!reservekey->GetReservedKey(pubkey)) return nullptr;
45 0 : return CreateNewBlockWithScript(GetScriptForDestination(pubkey.GetID()), pwallet);
46 : }
47 :
48 10606 : std::unique_ptr<CBlockTemplate> CreateNewBlockWithScript(const CScript& coinbaseScript, CWallet* pwallet)
49 : {
50 10606 : 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 10606 : if (Params().GetConsensus().NetworkUpgradeActive(nHeightNext, Consensus::UPGRADE_POS)) {
55 0 : 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 0 : MilliSleep((Params().GetConsensus().nTargetSpacing * 1000) >> 1);
58 10606 : return nullptr;
59 : }
60 :
61 21212 : return BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(coinbaseScript, pwallet, false);
62 : }
63 :
64 0 : bool ProcessBlockFound(const std::shared_ptr<const CBlock>& pblock, CWallet& wallet, std::unique_ptr<CReserveKey>& reservekey)
65 : {
66 0 : LogPrintf("%s\n", pblock->ToString());
67 0 : LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue));
68 :
69 : // Found a solution
70 0 : {
71 0 : WAIT_LOCK(g_best_block_mutex, lock);
72 0 : if (pblock->hashPrevBlock != g_best_block)
73 0 : return error("PIVXMiner : generated block is stale");
74 : }
75 :
76 : // Remove key from key pool
77 0 : if (reservekey)
78 0 : reservekey->KeepKey();
79 :
80 : // Process this block the same as if we had received it from another node
81 0 : BlockStateCatcherWrapper sc(pblock->GetHash());
82 0 : sc.registerEvent();
83 0 : bool res = ProcessNewBlock(pblock, nullptr);
84 0 : if (!res || sc.get().stateErrorFound()) {
85 0 : return error("PIVXMiner : ProcessNewBlock, block not accepted");
86 : }
87 :
88 0 : g_connman->ForEachNode([&pblock](CNode* node)
89 : {
90 0 : node->PushInventory(CInv(MSG_BLOCK, pblock->GetHash()));
91 0 : });
92 :
93 0 : return true;
94 : }
95 :
96 : bool fGenerateBitcoins = false;
97 : bool fStakeableCoins = false;
98 :
99 0 : void CheckForCoins(CWallet* pwallet, std::vector<CStakeableOutput>* availableCoins)
100 : {
101 0 : if (!pwallet || !pwallet->pStakerStatus)
102 : return;
103 :
104 : // control the amount of times the client will check for mintable coins (every block)
105 0 : {
106 0 : WAIT_LOCK(g_best_block_mutex, lock);
107 0 : if (g_best_block == pwallet->pStakerStatus->GetLastHash())
108 0 : return;
109 : }
110 0 : fStakeableCoins = pwallet->StakeableCoins(availableCoins);
111 : }
112 :
113 0 : void BitcoinMiner(CWallet* pwallet, bool fProofOfStake)
114 : {
115 0 : LogPrintf("PIVXMiner started\n");
116 0 : SetThreadPriority(THREAD_PRIORITY_LOWEST);
117 0 : util::ThreadRename("pivx-miner");
118 0 : const Consensus::Params& consensus = Params().GetConsensus();
119 0 : const int64_t nSpacingMillis = consensus.nTargetSpacing * 1000;
120 :
121 : // Each thread has its own key and counter
122 0 : std::unique_ptr<CReserveKey> pReservekey = fProofOfStake ? nullptr : std::make_unique<CReserveKey>(pwallet);
123 :
124 : // Available UTXO set
125 0 : std::vector<CStakeableOutput> availableCoins;
126 0 : unsigned int nExtraNonce = 0;
127 :
128 0 : while (fGenerateBitcoins || fProofOfStake) {
129 0 : CBlockIndex* pindexPrev = GetChainTip();
130 0 : if (!pindexPrev) {
131 0 : MilliSleep(nSpacingMillis); // sleep a block
132 0 : continue;
133 : }
134 0 : if (fProofOfStake) {
135 0 : if (!consensus.NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_POS)) {
136 : // The last PoW block hasn't even been mined yet.
137 0 : MilliSleep(nSpacingMillis); // sleep a block
138 0 : continue;
139 : }
140 :
141 : // update fStakeableCoins
142 0 : CheckForCoins(pwallet, &availableCoins);
143 :
144 0 : while ((g_connman && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && Params().MiningRequiresPeers())
145 0 : || pwallet->IsLocked() || !fStakeableCoins || masternodeSync.NotCompleted()) {
146 0 : MilliSleep(5000);
147 : // Do another check here to ensure fStakeableCoins is updated
148 0 : if (!fStakeableCoins) CheckForCoins(pwallet, &availableCoins);
149 : }
150 :
151 : //search our map of hashed blocks, see if bestblock has been hashed yet
152 0 : if (pwallet->pStakerStatus &&
153 0 : pwallet->pStakerStatus->GetLastHash() == pindexPrev->GetBlockHash() &&
154 0 : pwallet->pStakerStatus->GetLastTime() >= GetCurrentTimeSlot()) {
155 0 : MilliSleep(2000);
156 0 : continue;
157 : }
158 :
159 0 : } 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 0 : LogPrintf("%s: Exiting PoW Mining Thread at height: %d\n", __func__, pindexPrev->nHeight);
162 0 : return;
163 : }
164 :
165 : //
166 : // Create new block
167 : //
168 0 : unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
169 :
170 0 : std::unique_ptr<CBlockTemplate> pblocktemplate((fProofOfStake ?
171 0 : BlockAssembler(Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(CScript(), pwallet, true, &availableCoins) :
172 0 : CreateNewBlockWithKey(pReservekey, pwallet)));
173 0 : if (!pblocktemplate) continue;
174 0 : std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block);
175 :
176 : // POS - block found: process it
177 0 : if (fProofOfStake) {
178 0 : LogPrintf("%s : proof-of-stake block was signed %s \n", __func__, pblock->GetHash().ToString().c_str());
179 0 : SetThreadPriority(THREAD_PRIORITY_NORMAL);
180 0 : if (!ProcessBlockFound(pblock, *pwallet, pReservekey)) {
181 0 : LogPrintf("%s: New block orphaned\n", __func__);
182 0 : continue;
183 : }
184 0 : SetThreadPriority(THREAD_PRIORITY_LOWEST);
185 0 : continue;
186 : }
187 :
188 : // POW - miner main
189 0 : IncrementExtraNonce(pblock, pindexPrev->nHeight + 1, nExtraNonce);
190 :
191 0 : LogPrintf("Running PIVXMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
192 0 : ::GetSerializeSize(*pblock, PROTOCOL_VERSION));
193 :
194 : //
195 : // Search
196 : //
197 0 : int64_t nStart = GetTime();
198 0 : arith_uint256& hashTarget = arith_uint256().SetCompact(pblock->nBits);
199 0 : while (true) {
200 0 : unsigned int nHashesDone = 0;
201 :
202 0 : arith_uint256 hash;
203 0 : while (true) {
204 0 : hash = UintToArith256(pblock->GetHash());
205 0 : if (hash <= hashTarget) {
206 : // Found a solution
207 0 : SetThreadPriority(THREAD_PRIORITY_NORMAL);
208 0 : LogPrintf("%s:\n", __func__);
209 0 : LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
210 0 : ProcessBlockFound(pblock, *pwallet, pReservekey);
211 0 : SetThreadPriority(THREAD_PRIORITY_LOWEST);
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 0 : if (Params().IsRegTestNet())
216 0 : throw boost::thread_interrupted();
217 :
218 : break;
219 : }
220 0 : pblock->nNonce += 1;
221 0 : nHashesDone += 1;
222 0 : if ((pblock->nNonce & 0xFF) == 0)
223 : break;
224 : }
225 :
226 : // Meter hashes/sec
227 0 : static int64_t nHashCounter;
228 0 : if (nHPSTimerStart == 0) {
229 0 : nHPSTimerStart = GetTimeMillis();
230 0 : nHashCounter = 0;
231 : } else
232 0 : nHashCounter += nHashesDone;
233 0 : if (GetTimeMillis() - nHPSTimerStart > 4000) {
234 0 : static RecursiveMutex cs;
235 0 : {
236 0 : LOCK(cs);
237 0 : if (GetTimeMillis() - nHPSTimerStart > 4000) {
238 0 : dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
239 0 : nHPSTimerStart = GetTimeMillis();
240 0 : nHashCounter = 0;
241 0 : static int64_t nLogTime;
242 0 : if (GetTime() - nLogTime > 30 * 60) {
243 0 : nLogTime = GetTime();
244 0 : 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 0 : boost::this_thread::interruption_point();
252 0 : if ( (g_connman && g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0 && Params().MiningRequiresPeers()) || // Regtest mode doesn't require peers
253 0 : (pblock->nNonce >= 0xffff0000) ||
254 0 : (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) ||
255 0 : (pindexPrev != chainActive.Tip())
256 : ) break;
257 :
258 : // Update nTime every few seconds
259 0 : UpdateTime(pblock.get(), consensus, pindexPrev);
260 0 : if (Params().GetConsensus().fPowAllowMinDifficultyBlocks) {
261 : // Changing pblock->nTime can change work required on testnet:
262 0 : hashTarget.SetCompact(pblock->nBits);
263 : }
264 :
265 0 : }
266 : }
267 : }
268 :
269 0 : void static ThreadBitcoinMiner(void* parg)
270 : {
271 0 : boost::this_thread::interruption_point();
272 0 : CWallet* pwallet = (CWallet*)parg;
273 0 : try {
274 0 : BitcoinMiner(pwallet, false);
275 0 : boost::this_thread::interruption_point();
276 0 : } catch (const std::exception& e) {
277 0 : LogPrintf("PIVXMiner exception\n");
278 0 : } catch (...) {
279 0 : LogPrintf("PIVXMiner exception\n");
280 : }
281 :
282 0 : LogPrintf("PIVXMiner exiting\n");
283 0 : }
284 :
285 721 : void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
286 : {
287 721 : static boost::thread_group* minerThreads = nullptr;
288 721 : fGenerateBitcoins = fGenerate;
289 :
290 721 : if (minerThreads != nullptr) {
291 0 : minerThreads->interrupt_all();
292 0 : delete minerThreads;
293 0 : minerThreads = nullptr;
294 : }
295 :
296 721 : if (nThreads == 0 || !fGenerate)
297 : return;
298 :
299 0 : minerThreads = new boost::thread_group();
300 0 : for (int i = 0; i < nThreads; i++)
301 0 : minerThreads->create_thread(std::bind(&ThreadBitcoinMiner, pwallet));
302 : }
303 :
304 0 : void ThreadStakeMinter()
305 : {
306 0 : boost::this_thread::interruption_point();
307 0 : LogPrintf("ThreadStakeMinter started. Using wallet-0\n");
308 0 : CWallet* pwallet = vpwallets[0];
309 0 : try {
310 0 : BitcoinMiner(pwallet, true);
311 0 : boost::this_thread::interruption_point();
312 0 : } catch (const std::exception& e) {
313 0 : LogPrintf("ThreadStakeMinter() exception \n");
314 0 : } catch (...) {
315 0 : LogPrintf("ThreadStakeMinter() error \n");
316 : }
317 0 : LogPrintf("ThreadStakeMinter exiting,\n");
318 0 : }
319 :
320 : #endif // ENABLE_WALLET
|