]> Git Repo - VerusCoin.git/blame - src/miner.cpp
Remove debug outs
[VerusCoin.git] / src / miner.cpp
CommitLineData
d247a5d1 1// Copyright (c) 2009-2010 Satoshi Nakamoto
f914f1a7 2// Copyright (c) 2009-2014 The Bitcoin Core developers
78253fcb 3// Distributed under the MIT software license, see the accompanying
bc909a7a 4// file COPYING or https://www.opensource.org/licenses/mit-license.php .
d247a5d1 5
d247a5d1 6#include "miner.h"
8e8b6d70 7#ifdef ENABLE_MINING
c7aaab7a 8#include "pow/tromp/equi_miner.h"
2cc0a252 9#endif
51ed9ec9 10
eda37330 11#include "amount.h"
bebe7282 12#include "chainparams.h"
ca4a5f26 13#include "cc/StakeGuard.h"
20c3ac51 14#include "importcoin.h"
691161d4 15#include "consensus/consensus.h"
be126699 16#include "consensus/upgrades.h"
da29ecbc 17#include "consensus/validation.h"
8e8b6d70
JG
18#ifdef ENABLE_MINING
19#include "crypto/equihash.h"
42181656 20#include "crypto/verus_hash.h"
8e8b6d70 21#endif
85aab2a0 22#include "hash.h"
93bd00a0 23#include "key_io.h"
d247a5d1 24#include "main.h"
a6df7ab5 25#include "metrics.h"
51ed9ec9 26#include "net.h"
df852d2b 27#include "pow.h"
bebe7282 28#include "primitives/transaction.h"
8e165d57 29#include "random.h"
22c4272b 30#include "timedata.h"
8e8b6d70 31#include "ui_interface.h"
ad49c256
WL
32#include "util.h"
33#include "utilmoneystr.h"
b2993bc5 34#include "validationinterface.h"
09eb201b 35
df756d24
MT
36#include "zcash/Address.hpp"
37#include "transaction_builder.h"
38
fdda3c50
JG
39#include "sodium.h"
40
ad49c256 41#include <boost/thread.hpp>
a3c26c2e 42#include <boost/tuple/tuple.hpp>
8e8b6d70
JG
43#ifdef ENABLE_MINING
44#include <functional>
45#endif
5a360a5c 46#include <mutex>
ad49c256 47
2299bd95
MT
48#include "pbaas/pbaas.h"
49#include "pbaas/notarization.h"
b7c685b8 50#include "pbaas/identity.h"
e7e14f44 51#include "rpc/pbaasrpc.h"
13ed2980 52#include "transaction_builder.h"
2299bd95 53
09eb201b 54using namespace std;
7b4737c8 55
d247a5d1
JG
56//////////////////////////////////////////////////////////////////////////////
57//
58// BitcoinMiner
59//
60
c6cb21d1
GA
61//
62// Unconfirmed transactions in the memory pool often depend on other
63// transactions in the memory pool. When we select transactions from the
64// pool, we select by highest priority or fee rate, so we might consider
65// transactions that depend on transactions that aren't yet in the block.
66// The COrphan class keeps track of these 'temporary orphans' while
67// CreateBlock is figuring out which transactions to include.
68//
d247a5d1
JG
69class COrphan
70{
71public:
4d707d51 72 const CTransaction* ptx;
d247a5d1 73 set<uint256> setDependsOn;
c6cb21d1 74 CFeeRate feeRate;
02bec4b2 75 double dPriority;
e9e70b95 76
c6cb21d1 77 COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
d247a5d1 78 {
d247a5d1 79 }
d247a5d1
JG
80};
81
51ed9ec9
BD
82uint64_t nLastBlockTx = 0;
83uint64_t nLastBlockSize = 0;
d247a5d1 84
c6cb21d1
GA
85// We want to sort transactions by priority and fee rate, so:
86typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority;
d247a5d1
JG
87class TxPriorityCompare
88{
89 bool byFee;
e9e70b95 90
d247a5d1
JG
91public:
92 TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
e9e70b95 93
d247a5d1
JG
94 bool operator()(const TxPriority& a, const TxPriority& b)
95 {
96 if (byFee)
97 {
98 if (a.get<1>() == b.get<1>())
99 return a.get<0>() < b.get<0>();
100 return a.get<1>() < b.get<1>();
101 }
102 else
103 {
104 if (a.get<0>() == b.get<0>())
105 return a.get<1>() < b.get<1>();
106 return a.get<0>() < b.get<0>();
107 }
108 }
109};
110
bebe7282 111void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
22c4272b 112{
113 pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
5ead4b17
JG
114
115 // Updating time can change work required on testnet:
4c902704 116 if (consensusParams.nPowAllowMinDifficultyBlocksAfterHeight != boost::none) {
5ead4b17 117 pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
b86dc980 118 }
22c4272b 119}
120
5416af1d 121#include "komodo_defs.h"
122
69767347 123extern CCriticalSection cs_metrics;
c8d6a51c 124extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
48d800c2 125extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
5f63373e 126extern bool VERUS_MINTBLOCKS;
42181656 127extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
128extern const char *ASSETCHAINS_ALGORITHMS[];
56fe75cb 129extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
130extern uint32_t ASSETCHAINS_ALGO;
7c130297 131extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
b2a98c42
MT
132extern uint160 ASSETCHAINS_CHAINID;
133extern uint160 VERUS_CHAINID;
f2d873d0 134extern std::string VERUS_CHAINNAME;
68b309c0 135extern int32_t PBAAS_STARTBLOCK, PBAAS_ENDBLOCK;
7af5cf39 136extern string PBAAS_HOST, PBAAS_USERPASS, ASSETCHAINS_RPCHOST, ASSETCHAINS_RPCCREDENTIALS;;
f8f61a6d 137extern int32_t PBAAS_PORT;
7af5cf39 138extern uint16_t ASSETCHAINS_RPCPORT;
d9f176ac 139extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY;
292809f7 140void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
d9f176ac 141
94a465a6 142extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
31609f35 143uint32_t Mining_start, Mining_height;
28a62b60 144int32_t My_notaryid = -1;
8683bd8d 145int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
b4810651 146int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize);
d63fdb34 147int32_t komodo_baseid(char *origbase);
3bc88f14 148int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
29bd53a1 149int64_t komodo_block_unlocktime(uint32_t nHeight);
18443f69 150uint64_t komodo_commission(const CBlock *block);
d231a6a7 151int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig);
855714b0 152int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, std::vector<unsigned char> &utxosig, CTxDestination &rewardDest);
496f1fd2 153int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
7652ed92 154
1685bba0
MT
155void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int &nExtraNonce, bool buildMerkle, uint32_t *pSaveBits)
156{
157 // Update nExtraNonce
158 static uint256 hashPrevBlock;
159 if (hashPrevBlock != pblock->hashPrevBlock)
160 {
161 nExtraNonce = 0;
162 hashPrevBlock = pblock->hashPrevBlock;
163 }
164 ++nExtraNonce;
165
166 if (pSaveBits)
167 {
168 *pSaveBits = pblock->nBits;
169 }
170
171 int32_t nHeight = pindexPrev->GetHeight() + 1;
172
d3dfc922 173 int solutionVersion = CConstVerusSolutionVector::activationHeight.ActiveVersion(nHeight);
174
175 if (solutionVersion >= CConstVerusSolutionVector::activationHeight.ACTIVATE_PBAAS_HEADER)
1685bba0
MT
176 {
177 // coinbase should already be finalized in the new version
178 if (buildMerkle)
179 {
180 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
af521e42 181 pblock->SetPrevMMRRoot(ChainMerkleMountainView(chainActive.GetMMR(), pindexPrev->GetHeight()).GetRoot());
2d88a342 182 BlockMMRange mmRange(pblock->BuildBlockMMRTree());
56fe75cb 183 BlockMMView mmView(mmRange);
184 pblock->SetBlockMMRRoot(mmView.GetRoot());
185 pblock->AddUpdatePBaaSHeader();
1685bba0
MT
186 }
187
188 UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
189
1685bba0
MT
190 // POS blocks have already had their solution space filled, and there is no actual extra nonce, extradata is used
191 // for POS proof, so don't modify it
d3dfc922 192 if (solutionVersion >= CConstVerusSolutionVector::activationHeight.ACTIVATE_PBAAS && !pblock->IsVerusPOSBlock())
1685bba0 193 {
d3dfc922 194 pblock->AddUpdatePBaaSHeader();
195
1685bba0
MT
196 uint8_t dummy;
197 // clear extra data to allow adding more PBaaS headers
198 pblock->SetExtraData(&dummy, 0);
199
200 // combine blocks and set compact difficulty if necessary
201 uint32_t savebits;
202 if ((savebits = ConnectedChains.CombineBlocks(*pblock)) && pSaveBits)
203 {
204 arith_uint256 ours, merged;
205 ours.SetCompact(pblock->nBits);
206 merged.SetCompact(savebits);
207 if (merged > ours)
208 {
209 *pSaveBits = savebits;
210 }
211 }
212
213 // extra nonce is kept in the header, not in the coinbase any longer
214 // this allows instant spend transactions to use coinbase funds for
215 // inputs by ensuring that once final, the coinbase transaction hash
216 // will not continue to change
217 CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
218 s << nExtraNonce;
219 std::vector<unsigned char> vENonce(s.begin(), s.end());
220
221 assert(pblock->ExtraDataLen() >= vENonce.size());
222 pblock->SetExtraData(vENonce.data(), vENonce.size());
223 }
224 }
225 else
226 {
227 // finalize input of coinbase
228 CMutableTransaction txcb(pblock->vtx[0]);
229 txcb.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS;
230 assert(txcb.vin[0].scriptSig.size() <= 100);
231 pblock->vtx[0] = txcb;
232 if (buildMerkle)
233 {
234 pblock->hashMerkleRoot = pblock->BuildMerkleTree();
235 }
236
237 UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
238 }
239}
240
a4f9bc97 241extern CWallet *pwalletMain;
242
243CPubKey GetSolutionPubKey(const std::vector<std::vector<unsigned char>> &vSolutions, txnouttype txType)
244{
245 CPubKey pk;
246
247 if (txType == TX_PUBKEY)
248 {
249 pk = CPubKey(vSolutions[0]);
250 }
251 else if(txType == TX_PUBKEYHASH)
252 {
253 // we need to have this in our wallet to get the public key
254 LOCK(pwalletMain->cs_wallet);
255 pwalletMain->GetPubKey(CKeyID(uint160(vSolutions[0])), pk);
256 }
257 else if (txType == TX_CRYPTOCONDITION)
258 {
259 if (vSolutions[0].size() == 33)
260 {
261 pk = CPubKey(vSolutions[0]);
262 }
263 else if (vSolutions[0].size() == 34 && vSolutions[0][0] == COptCCParams::ADDRTYPE_PK)
264 {
265 pk = CPubKey(std::vector<unsigned char>(vSolutions[0].begin() + 1, vSolutions[0].end()));
266 }
267 else if (vSolutions[0].size() == 20)
268 {
269 LOCK(pwalletMain->cs_wallet);
270 pwalletMain->GetPubKey(CKeyID(uint160(vSolutions[0])), pk);
271 }
272 else if (vSolutions[0].size() == 21 && vSolutions[0][0] == COptCCParams::ADDRTYPE_ID)
273 {
274 // destination is an identity, see if we can get its first public key
275 std::pair<CIdentityMapKey, CIdentityMapValue> identity;
276
277 if (pwalletMain->GetIdentity(CIdentityID(uint160(std::vector<unsigned char>(vSolutions[0].begin() + 1, vSolutions[0].end()))), identity) &&
278 identity.second.IsValidUnrevoked() &&
279 identity.second.primaryAddresses.size())
280 {
281 CPubKey pkTmp = boost::apply_visitor<GetPubKeyForPubKey>(GetPubKeyForPubKey(), identity.second.primaryAddresses[0]);
282 if (pkTmp.IsValid())
283 {
284 pk = pkTmp;
285 }
286 else
287 {
288 LOCK(pwalletMain->cs_wallet);
289 pwalletMain->GetPubKey(CKeyID(GetDestinationID(identity.second.primaryAddresses[0])), pk);
290 }
291 }
292 }
293 }
294 return pk;
295}
296
297CPubKey GetScriptPublicKey(const CScript &scriptPubKey)
298{
299 txnouttype typeRet;
300 std::vector<std::vector<unsigned char>> vSolutions;
301 if (Solver(scriptPubKey, typeRet, vSolutions))
302 {
303 return GetSolutionPubKey(vSolutions, typeRet);
304 }
305 return CPubKey();
306}
307
c8c684e9 308// call a chain that we consider a notary chain, meaning we call its daemon, not the other way around,
42bbe8d7 309// retrieve new exports that we have not imported, and process them. Also, send any exports that are now
310// provable with the available notarization on the specified chain.
c8c684e9 311void ProcessNewImports(const uint160 &sourceChainID, CPBaaSNotarization &lastConfirmed, CUTXORef &lastConfirmedUTXO, uint32_t nHeight)
a041b57e 312{
2f416b17 313 if (CConstVerusSolutionVector::GetVersionByHeight(nHeight) < CActivationHeight::ACTIVATE_PBAAS ||
314 CConstVerusSolutionVector::activationHeight.IsActivationHeight(CActivationHeight::ACTIVATE_PBAAS, nHeight))
315 {
316 return;
317 }
c8c684e9 318
a041b57e 319 uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
320
321 // get any pending imports from the source chain. if the source chain is this chain, we don't need notarization
322 CCurrencyDefinition thisChain = ConnectedChains.ThisChain();
918dc9e0 323 uint160 thisChainID = thisChain.GetID();
c8c684e9 324 CCurrencyDefinition sourceChain = ConnectedChains.GetCachedCurrency(sourceChainID);
325 if (!sourceChain.IsValid())
326 {
327 printf("Unrecognized source chain %s\n", EncodeDestination(CIdentityID(sourceChainID)).c_str());
328 return;
329 }
330
e57a7325 331 // printf("%s: processing imports for %s\n", __func__, sourceChain.name.c_str());
cdff02e5 332
c8c684e9 333 bool isSameChain = thisChain.GetID() == sourceChainID;
334
335 CChainNotarizationData cnd;
99e865c3 336 if (!(GetNotarizationData(sourceChainID, cnd) && cnd.IsConfirmed()))
c8c684e9 337 {
338 printf("Cannot get notarization data for currency %s\n", sourceChain.name.c_str());
339 return;
340 }
341
342 lastConfirmedUTXO = cnd.vtx[cnd.lastConfirmed].first;
343 lastConfirmed = cnd.vtx[cnd.lastConfirmed].second;
a041b57e 344
345 CTransaction lastImportTx;
346
347 // we need to find the last unspent import transaction
348 std::vector<CAddressUnspentDbEntry> unspentOutputs;
349
350 bool found = false;
c8c684e9 351 CAddressUnspentDbEntry foundEntry;
352 CCrossChainImport lastCCI;
353 std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>> exports;
a041b57e 354
a041b57e 355 {
c8c684e9 356 LOCK(cs_main);
357
358 if (!isSameChain &&
5d75d90d 359 lastConfirmed.proofRoots.count(sourceChainID) &&
360 GetAddressUnspent(CKeyID(CCrossChainRPCData::GetConditionID(sourceChainID, CCrossChainImport::CurrencySystemImportKey())), CScript::P2IDX, unspentOutputs))
a041b57e 361 {
c8c684e9 362 // if one spends the prior one, get the one that is not spent
363 for (auto &txidx : unspentOutputs)
364 {
365 COptCCParams p;
366 if (txidx.second.script.IsPayToCryptoCondition(p) &&
367 p.IsValid() &&
368 p.evalCode == EVAL_CROSSCHAIN_IMPORT &&
369 p.vData.size() &&
370 (lastCCI = CCrossChainImport(p.vData[0])).IsValid())
371 {
372 found = true;
373 foundEntry = txidx;
374 break;
375 }
376 }
377
378 if (found &&
c8c684e9 379 lastCCI.sourceSystemHeight < lastConfirmed.notarizationHeight)
a041b57e 380 {
c8c684e9 381 UniValue params(UniValue::VARR);
382
918dc9e0 383 params.push_back(EncodeDestination(CIdentityID(thisChainID)));
c8c684e9 384 params.push_back((int64_t)lastCCI.sourceSystemHeight);
4c26b35c 385 params.push_back((int64_t)lastConfirmed.proofRoots[sourceChainID].rootHeight);
c8c684e9 386
387 UniValue result = NullUniValue;
388 try
389 {
390 if (sourceChainID == thisChain.GetID())
391 {
392 UniValue getexports(const UniValue& params, bool fHelp);
393 result = getexports(params, false);
394 }
395 else
396 {
397 result = find_value(RPCCallRoot("getexports", params), "result");
398 }
399 } catch (exception e)
400 {
401 printf("Could not get latest export from external chain %s\n", uni_get_str(params[0]).c_str());
402 return;
403 }
404
405 // now, we should have a list of exports to import in order
406 if (!result.isArray() || !result.size())
407 {
408 return;
409 }
179b6f82 410 bool foundCurrent = false;
c8c684e9 411 for (int i = 0; i < result.size(); i++)
412 {
179b6f82 413 uint256 exportTxId = uint256S(uni_get_str(find_value(result[i], "txid")));
414 if (!foundCurrent && !lastCCI.exportTxId.IsNull())
415 {
416 // when we find our export, take the next
417 if (exportTxId == lastCCI.exportTxId)
418 {
419 foundCurrent = true;
420 }
421 continue;
422 }
423
c8c684e9 424 // create one import at a time
425 uint32_t notarizationHeight = uni_get_int64(find_value(result[i], "height"));
c8c684e9 426 int32_t exportTxOutNum = uni_get_int(find_value(result[i], "txoutnum"));
427 CPartialTransactionProof txProof = CPartialTransactionProof(find_value(result[i], "partialtransactionproof"));
428 UniValue transferArrUni = find_value(result[i], "transfers");
429 if (!notarizationHeight ||
430 exportTxId.IsNull() ||
431 exportTxOutNum == -1 ||
432 !transferArrUni.isArray())
433 {
434 printf("Invalid export from %s\n", uni_get_str(params[0]).c_str());
435 return;
436 }
437
438 CTransaction exportTx;
439 uint256 blkHash;
440 auto proofRootIt = lastConfirmed.proofRoots.find(sourceChainID);
441 if (!isSameChain &&
442 !(txProof.IsValid() &&
51a9c83c 443 !txProof.GetPartialTransaction(exportTx).IsNull() &&
444 txProof.TransactionHash() == exportTxId &&
445 proofRootIt != lastConfirmed.proofRoots.end() &&
446 proofRootIt->second.stateRoot == txProof.CheckPartialTransaction(exportTx) &&
447 exportTx.vout.size() > exportTxOutNum))
c8c684e9 448 {
e7c64795 449 /* printf("%s: proofRoot: %s, checkPartialRoot: %s, proofheight: %u, ischainproof: %s, blockhash: %s\n",
4c26b35c 450 __func__,
451 proofRootIt->second.ToUniValue().write(1,2).c_str(),
452 txProof.CheckPartialTransaction(exportTx).GetHex().c_str(),
5d75d90d 453 txProof.GetProofHeight(),
4c26b35c 454 txProof.IsChainProof() ? "true" : "false",
e7c64795 455 txProof.GetBlockHash().GetHex().c_str()); */
5d75d90d 456 printf("Invalid export for %s\n", uni_get_str(params[0]).c_str());
c8c684e9 457 return;
458 }
459 else if (isSameChain &&
460 !(myGetTransaction(exportTxId, exportTx, blkHash) &&
461 exportTx.vout.size() > exportTxOutNum))
462 {
463 printf("Invalid export msg2 from %s\n", uni_get_str(params[0]).c_str());
464 return;
465 }
179b6f82 466 if (!foundCurrent)
467 {
468 CCrossChainExport ccx(exportTx.vout[exportTxOutNum].scriptPubKey);
469 if (!ccx.IsValid())
470 {
471 printf("Invalid export msg3 from %s\n", uni_get_str(params[0]).c_str());
472 return;
473 }
474 if (ccx.IsChainDefinition())
475 {
476 continue;
477 }
478 }
c8c684e9 479 std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>> oneExport =
480 std::make_pair(std::make_pair(CInputDescriptor(exportTx.vout[exportTxOutNum].scriptPubKey,
481 exportTx.vout[exportTxOutNum].nValue,
482 CTxIn(exportTxId, exportTxOutNum)),
483 txProof),
484 std::vector<CReserveTransfer>());
485 for (int j = 0; j < transferArrUni.size(); j++)
486 {
5d75d90d 487 //printf("%s: onetransfer: %s\n", __func__, transferArrUni[j].write(1,2).c_str());
488 oneExport.second.push_back(CReserveTransfer(transferArrUni[j]));
c8c684e9 489 if (!oneExport.second.back().IsValid())
490 {
5d75d90d 491 printf("Invalid reserve transfers in export from %s\n", sourceChain.name.c_str());
c8c684e9 492 return;
493 }
494 }
cdff02e5 495 exports.push_back(oneExport);
c8c684e9 496 }
a041b57e 497 }
c8c684e9 498 std::map<uint160, std::vector<std::pair<int, CTransaction>>> newImports;
499 ConnectedChains.CreateLatestImports(sourceChain, lastConfirmedUTXO, exports, newImports);
500 }
501 else if (isSameChain)
502 {
503 ConnectedChains.ProcessLocalImports();
504 return;
505 }
506 else
507 {
508 printf("Could not get prior import for currency %s\n", sourceChain.name.c_str());
509 return;
a041b57e 510 }
511 }
c8c684e9 512}
a041b57e 513
c8c684e9 514bool CheckNotaryConnection(const CRPCChainData &notarySystem)
515{
516 // ensure we have connection parameters, or we fail
517 if (notarySystem.rpcHost == "" || notarySystem.rpcUserPass == "" || !notarySystem.rpcPort)
518 {
519 return false;
520 }
521 return true;
522}
523
524bool CallNotary(const CRPCChainData &notarySystem, std::string command, const UniValue &params, UniValue &result, UniValue &error)
525{
526 // ensure we have connection parameters, or we fail
527 if (!CheckNotaryConnection(notarySystem))
528 {
529 return false;
530 }
531
532 try
533 {
534 UniValue rpcResult = RPCCall(command, params, notarySystem.rpcUserPass, notarySystem.rpcPort, notarySystem.rpcHost);
535 result = find_value(rpcResult, "result");
536 error = find_value(rpcResult, "error");
537 } catch (std::exception e)
a041b57e 538 {
c8c684e9 539 error = strprintf("Failed to connect to %s chain, error: %s\n", notarySystem.chainDefinition.name.c_str(), e.what());
540 }
541 return error.isNull();
542}
543
544// get initial currency state from the notary system specified
203d1021 545bool GetBlockOneLaunchNotarization(const CRPCChainData &notarySystem,
546 const uint160 &currencyID,
547 CCurrencyDefinition &curDef,
548 CPBaaSNotarization &launchNotarization,
e7c64795 549 CPBaaSNotarization &notaryNotarization,
0b1a0e7f 550 std::pair<CUTXORef, CPartialTransactionProof> &notarizationOutputProof,
a36e0d92 551 std::pair<CUTXORef, CPartialTransactionProof> &exportOutputProof,
552 std::vector<CReserveTransfer> &exportTransfers)
c8c684e9 553{
554 UniValue result, error;
203d1021 555 bool retVal = false;
a041b57e 556
c8c684e9 557 UniValue params(UniValue::VARR);
558 params.push_back(EncodeDestination(CIdentityID(currencyID)));
559
560 // VRSC and VRSCTEST do not start with a notary chain
40dc0bda 561 if (!IsVerusActive() && ConnectedChains.IsNotaryAvailable())
c8c684e9 562 {
563 // we are starting a PBaaS chain. We only assume that our chain definition and the first notary chain, if there is one, are setup
564 // in ConnectedChains. All other currencies and identities necessary to start have not been populated and must be in block 1 by
565 // getting the information from the notary chain.
203d1021 566 if (CallNotary(notarySystem, "getlaunchinfo", params, result, error))
a041b57e 567 {
203d1021 568 CCurrencyDefinition currency(find_value(result, "currencydefinition"));
e7c64795 569 CPBaaSNotarization notarization(find_value(result, "launchnotarization"));
570 notaryNotarization = CPBaaSNotarization(find_value(result, "notarynotarization"));
0b1a0e7f 571 CPartialTransactionProof notarizationProof(find_value(result, "notarizationproof"));
572 CUTXORef notarizationUtxo(uint256S(uni_get_str(find_value(result, "notarizationtxid"))), uni_get_int(find_value(result, "notarizationvoutnum")));
573
574 CPartialTransactionProof exportProof(find_value(result, "exportproof"));
a36e0d92 575 UniValue exportTransfersUni = find_value(result, "exportransfers");
576
577 bool reject = false;
578 if (exportTransfersUni.isArray() && exportTransfersUni.size())
579 {
580 for (int i = 0; i < exportTransfersUni.size(); i++)
581 {
582 CReserveTransfer oneTransfer(exportTransfersUni[i]);
583 if (!oneTransfer.IsValid())
584 {
585 reject = true;
586 }
587 else
588 {
589 exportTransfers.push_back(oneTransfer);
590 }
591 }
592 }
0b1a0e7f 593 CUTXORef exportUtxo(uint256S(uni_get_str(find_value(result, "exporttxid"))), uni_get_int(find_value(result, "exportvoutnum")));
594
a36e0d92 595 if (reject ||
596 !currency.IsValid() ||
203d1021 597 !notarization.IsValid() ||
5d75d90d 598 !notarizationProof.IsValid() ||
e7c64795 599 !notaryNotarization.IsValid())
c8c684e9 600 {
203d1021 601 LogPrintf("%s: invalid launch notarization for currency %s\n", __func__, EncodeDestination(CIdentityID(currencyID)).c_str());
b4ba7e7c 602 printf("%s: invalid launch notarization for currency %s\ncurrencydefinition: %s\nnotarization: %s\ntransactionproof: %s\n",
603 __func__,
604 EncodeDestination(CIdentityID(currencyID)).c_str(),
605 currency.ToUniValue().write(1,2).c_str(),
606 notarization.ToUniValue().write(1,2).c_str(),
0b1a0e7f 607 notarizationProof.ToUniValue().write(1,2).c_str());
203d1021 608 }
609 else
610 {
5d75d90d 611 //printf("%s: proofroot: %s\n", __func__, latestProofRoot.ToUniValue().write(1,2).c_str());
203d1021 612 curDef = currency;
613 launchNotarization = notarization;
e7c64795 614 launchNotarization.proofRoots = notaryNotarization.proofRoots;
615 notaryNotarization.proofRoots[ASSETCHAINS_CHAINID] = CProofRoot::GetProofRoot(0);
616 notaryNotarization.currencyStates[ASSETCHAINS_CHAINID] = launchNotarization.currencyState;
0b1a0e7f 617 notarizationOutputProof = std::make_pair(notarizationUtxo, notarizationProof);
618 exportOutputProof = std::make_pair(exportUtxo, exportProof);
203d1021 619 retVal = true;
a041b57e 620 }
621 }
203d1021 622 else
623 {
624 LogPrintf("%s: error calling notary chain %s\n", __func__, error.write(1,2).c_str());
625 printf("%s: error calling notary chain %s\n", __func__, error.write(1,2).c_str());
626 }
c8c684e9 627 }
203d1021 628 return retVal;
c8c684e9 629}
630
6f40dc90 631bool DecodeOneExport(const UniValue obj, CCrossChainExport &ccx,
632 std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>> &oneExport)
633{
634 uint32_t exportHeight = uni_get_int64(find_value(obj, "height"));
635 uint256 txId = uint256S(uni_get_str(find_value(obj, "txid")));
636 uint32_t outNum = uni_get_int(find_value(obj, "txoutnum"));
637 ccx = CCrossChainExport(find_value(obj, "exportinfo"));
638 if (!ccx.IsValid())
639 {
640 LogPrintf("%s: invalid launch export from notary chain\n", __func__);
641 printf("%s: invalid launch export from notary chain\n", __func__);
642 return false;
643 }
644 CPartialTransactionProof partialTxProof(find_value(obj, "partialtransactionproof"));
645 CTransaction exportTx;
646 COptCCParams p;
647 CScript outputScript;
648 CAmount outputValue;
649
0b1a0e7f 650 // TODO: HARDENING - check the proof against the actual notarization here
6f40dc90 651 if (!partialTxProof.IsValid() ||
51a9c83c 652 partialTxProof.GetPartialTransaction(exportTx).IsNull() ||
653 partialTxProof.TransactionHash() != txId ||
6f40dc90 654 exportTx.vout.size() <= outNum ||
655 !exportTx.vout[outNum].scriptPubKey.IsPayToCryptoCondition(p) ||
656 !p.IsValid() ||
657 !p.evalCode == EVAL_CROSSCHAIN_EXPORT ||
658 (outputValue = exportTx.vout[outNum].nValue) == -1)
659 {
0b1a0e7f 660 //UniValue jsonTxOut(UniValue::VOBJ);
661 //TxToUniv(exportTx, uint256(), jsonTxOut);
51a9c83c 662 //printf("%s: proofTxRoot:%s\npartialTx: %s\n", __func__,
663 // partialTxProof.GetPartialTransaction(exportTx).GetHex().c_str(),
664 // jsonTxOut.write(1,2).c_str());
6f40dc90 665 LogPrintf("%s: invalid partial transaction proof from notary chain\n", __func__);
666 printf("%s: invalid partial transaction proof from notary chain\n", __func__);
667 return false;
668 }
669
670 UniValue transfers = find_value(obj, "transfers");
671 std::vector<CReserveTransfer> reserveTransfers;
672 if (transfers.isArray() && transfers.size())
673 {
674 for (int i = 0; i < transfers.size(); i++)
675 {
676 CReserveTransfer rt(transfers[i]);
677 if (rt.IsValid())
678 {
679 reserveTransfers.push_back(rt);
680 }
681 }
682 }
683
684 oneExport.first.first = CInputDescriptor(outputScript, outputValue, CTxIn(txId, outNum));
685 oneExport.first.second = partialTxProof;
686 oneExport.second = reserveTransfers;
687 return true;
688}
689
690// get initial currency state from the notary system specified
5d75d90d 691bool GetBlockOneImports(const CRPCChainData &notarySystem, const CPBaaSNotarization &launchNotarization, std::map<uint160, std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>>> &exports)
6f40dc90 692{
693 UniValue result, error;
694
695 UniValue params(UniValue::VARR);
696 params.push_back(EncodeDestination(CIdentityID(ASSETCHAINS_CHAINID)));
5d75d90d 697 params.push_back((int)0);
698 if (launchNotarization.proofRoots.count(ConnectedChains.ThisChain().launchSystemID))
699 {
700 params.push_back((int64_t)launchNotarization.proofRoots.find(ConnectedChains.ThisChain().launchSystemID)->second.rootHeight);
701 }
6f40dc90 702
703 // VRSC and VRSCTEST do not start with a notary chain
704 if (!IsVerusActive() && ConnectedChains.IsNotaryAvailable())
705 {
706 // we are starting a PBaaS chain. We only assume that our chain definition and the first notary chain, if there is one, are setup
707 // in ConnectedChains. All other currencies and identities necessary to start have not been populated and must be in block 1 by
708 // getting the information from the notary chain.
709 if (CallNotary(notarySystem, "getexports", params, result, error) &&
710 result.isArray() &&
711 result.size())
712 {
713 // we now have an array of exports that we should import into this system
714 // load up to the last launch export on each currency
715 for (int i = 0; i < result.size(); i++)
716 {
717 CCrossChainExport ccx;
718 std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>> oneExport;
237ab583 719 if (DecodeOneExport(result[i], ccx, oneExport))
6f40dc90 720 {
721 exports[ccx.destCurrencyID].push_back(oneExport);
722 }
723 else
724 {
725 return false;
726 }
727 }
728 return true;
729 }
730 return false;
731 }
732 return false;
733}
734
c8c684e9 735// This is called with either the initial currency, or the gateway converter currency
736// to setup an import/export thread, transfer the initial issuance of native currency
737// into the converter, and notarize the state of each currency.
738// All outputs to do those things are added to the outputs vector.
37434dab 739bool AddOneCurrencyImport(const CCurrencyDefinition &newCurrency,
6f40dc90 740 const CPBaaSNotarization &lastNotarization,
203d1021 741 const std::pair<CUTXORef, CPartialTransactionProof> *pLaunchProof,
0b1a0e7f 742 const std::pair<CUTXORef, CPartialTransactionProof> *pFirstExport,
a36e0d92 743 const std::vector<CReserveTransfer> &_exportTransfers,
e6c5e0b8 744 CCurrencyValueMap &gatewayDeposits,
24d12992 745 std::vector<CTxOut> &outputs,
746 CCurrencyValueMap &additionalFees)
c8c684e9 747{
748 uint160 newCurID = newCurrency.GetID();
37434dab 749 CPBaaSNotarization newNotarization = lastNotarization;
750 newNotarization.prevNotarization = CUTXORef();
923bb2c0 751 newNotarization.SetBlockOneNotarization();
a041b57e 752
c8c684e9 753 // each currency will get:
754 // * one currency definition output
755 // * notarization of latest currency state
756
757 CCcontract_info CC;
758 CCcontract_info *cp;
759
37434dab 760 // make a currency definition
c8c684e9 761 cp = CCinit(&CC, EVAL_CURRENCY_DEFINITION);
762 std::vector<CTxDestination> dests({CPubKey(ParseHex(CC.CChexstr))});
763 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCurrencyDefinition>(EVAL_CURRENCY_DEFINITION, dests, 1, &newCurrency))));
764
765 // import / export capable currencies include the main currency, fractional currencies on any system,
c3292082 766 // gateway currencies. the launch system, and non-token currencies. they also get an import / export thread
767 if (ConnectedChains.ThisChain().launchSystemID == newCurID ||
768 (newCurrency.systemID == ASSETCHAINS_CHAINID &&
a9c8cca3 769 (newCurrency.IsFractional() ||
e7c64795 770 newCurrency.systemID == newCurID ||
c3292082 771 (newCurrency.IsGateway() && newCurrency.GetID() == newCurrency.gatewayID))))
c8c684e9 772 {
37434dab 773 uint160 firstNotaryID = ConnectedChains.FirstNotaryChain().chainDefinition.GetID();
774
203d1021 775 // first, put evidence of the notarization pre-import
0b1a0e7f 776 int notarizationIdx = -1;
203d1021 777 if (pLaunchProof)
778 {
779 // add notarization before other outputs
780 cp = CCinit(&CC, EVAL_NOTARY_EVIDENCE);
781 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
782 // now, we need to put the launch notarization evidence, followed by the import outputs
783 CNotaryEvidence evidence = CNotaryEvidence(ConnectedChains.FirstNotaryChain().chainDefinition.GetID(),
784 pLaunchProof->first,
785 true,
786 std::map<CIdentityID, CIdentitySignature>(),
787 std::vector<CPartialTransactionProof>({pLaunchProof->second}),
788 CNotaryEvidence::TYPE_PARTIAL_TXPROOF);
0b1a0e7f 789 notarizationIdx = outputs.size();
203d1021 790 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CNotaryEvidence>(EVAL_NOTARY_EVIDENCE, dests, 1, &evidence))));
791 }
792
a36e0d92 793 // create the import thread output
794 cp = CCinit(&CC, EVAL_CROSSCHAIN_IMPORT);
795 if (newCurrency.proofProtocol == newCurrency.PROOF_CHAINID)
796 {
797 dests = std::vector<CTxDestination>({CIdentityID(newCurID)});
798 }
799 else
800 {
801 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
802 }
803
c3292082 804 if ((newCurrency.systemID == ASSETCHAINS_CHAINID) && firstNotaryID == newCurrency.launchSystemID)
37434dab 805 {
37434dab 806 uint256 transferHash;
807 std::vector<CTxOut> importOutputs;
808 CCurrencyValueMap importedCurrency, gatewayDepositsUsed, spentCurrencyOut;
809
40dc0bda 810 CPBaaSNotarization tempLastNotarization = lastNotarization;
db616a05 811 tempLastNotarization.currencyState.SetLaunchCompleteMarker(false);
40dc0bda 812
a36e0d92 813 std::vector<CReserveTransfer> exportTransfers(_exportTransfers);
40dc0bda 814 if (!tempLastNotarization.NextNotarizationInfo(ConnectedChains.FirstNotaryChain().chainDefinition,
815 newCurrency,
816 0,
db616a05 817 1,
40dc0bda 818 exportTransfers,
819 transferHash,
820 newNotarization,
821 importOutputs,
822 importedCurrency,
823 gatewayDepositsUsed,
824 spentCurrencyOut))
37434dab 825 {
826 LogPrintf("%s: invalid import for currency %s on system %s\n", __func__,
827 newCurrency.name.c_str(),
828 EncodeDestination(CIdentityID(ASSETCHAINS_CHAINID)).c_str());
829 return false;
830 }
40dc0bda 831
a36e0d92 832 // if fees are not converted, we will pay out original fees,
833 // less liquidity fees, which go into the currency reserves
834 bool feesConverted;
835 CCurrencyValueMap liquidityFees;
836 CCurrencyValueMap originalFees =
837 newNotarization.currencyState.CalculateConvertedFees(
838 newNotarization.currencyState.viaConversionPrice,
839 newNotarization.currencyState.viaConversionPrice,
840 ASSETCHAINS_CHAINID,
841 feesConverted,
842 liquidityFees,
843 additionalFees);
844
845 if (!feesConverted)
24d12992 846 {
a36e0d92 847 additionalFees += (originalFees - liquidityFees);
24d12992 848 }
849
923bb2c0 850 newNotarization.SetBlockOneNotarization();
851
b4ba7e7c 852 // display import outputs
a3c9294b 853 CMutableTransaction debugTxOut;
24d12992 854 debugTxOut.vout = outputs;
855 debugTxOut.vout.insert(debugTxOut.vout.end(), importOutputs.begin(), importOutputs.end());
40dc0bda 856 UniValue jsonTxOut(UniValue::VOBJ);
857 TxToUniv(debugTxOut, uint256(), jsonTxOut);
858 printf("%s: launch outputs: %s\nlast notarization: %s\nnew notarization: %s\n", __func__,
859 jsonTxOut.write(1,2).c_str(),
860 lastNotarization.ToUniValue().write(1,2).c_str(),
861 newNotarization.ToUniValue().write(1,2).c_str());
a3c9294b 862
37434dab 863 newNotarization.prevNotarization = CUTXORef();
864 newNotarization.prevHeight = 0;
c8c684e9 865
6f40dc90 866 // get the first export for launch from the notary chain
0b1a0e7f 867 CTransaction firstExportTx;
dc51c829 868 if (!pFirstExport || !(pFirstExport->second.IsValid() && !pFirstExport->second.GetPartialTransaction(firstExportTx).IsNull()))
6f40dc90 869 {
0b1a0e7f 870 LogPrintf("%s: invalid first export for PBaaS or converter launch\n");
6f40dc90 871 return false;
872 }
873
874 // get the export for this import
0b1a0e7f 875 CCrossChainExport ccx(firstExportTx.vout[pFirstExport->first.n].scriptPubKey);
876 if (!ccx.IsValid())
877 {
878 LogPrintf("%s: invalid export output for PBaaS or converter launch\n");
879 return false;
880 }
6f40dc90 881
faffe06c 882 // create an import based on launch conditions that covers all pre-allocations and uses the initial notarization.
6f40dc90 883 // generate outputs, then fill in numOutputs
c8c684e9 884 CCrossChainImport cci = CCrossChainImport(newCurrency.launchSystemID,
37434dab 885 newNotarization.notarizationHeight,
c8c684e9 886 newCurID,
6f40dc90 887 ccx.totalAmounts,
888 CCurrencyValueMap(),
889 0,
890 ccx.hashReserveTransfers,
dc51c829 891 pFirstExport->first.hash,
0b1a0e7f 892 pFirstExport->first.n);
6f40dc90 893 cci.SetSameChain(newCurrency.launchSystemID == ASSETCHAINS_CHAINID);
cdff02e5 894 cci.SetPostLaunch();
40dc0bda 895 cci.SetInitialLaunchImport();
c8c684e9 896
e6c5e0b8 897 // anything we had before plus anything imported and minus all spent currency out should
898 // be all reserve deposits remaining under control of this currency
899
136f16ad 900 /* printf("%s: ccx.totalAmounts: %s\ngatewayDepositsUsed: %s\nadditionalFees: %s\noriginalFees: %s\n",
a36e0d92 901 __func__,
902 ccx.totalAmounts.ToUniValue().write(1,2).c_str(),
903 gatewayDepositsUsed.ToUniValue().write(1,2).c_str(),
136f16ad 904 additionalFees.ToUniValue().write(1,2).c_str(),
905 originalFees.ToUniValue().write(1,2).c_str()); */
e6c5e0b8 906
907 // to determine left over reserves for deposit, consider imported and emitted as the same
136f16ad 908 gatewayDeposits = CCurrencyValueMap(lastNotarization.currencyState.currencies, lastNotarization.currencyState.reserveIn);
909 if (!newCurrency.IsFractional())
a36e0d92 910 {
136f16ad 911 gatewayDeposits += originalFees;
e6c5e0b8 912 }
ca768726 913
a36e0d92 914 gatewayDeposits.valueMap[newCurID] += newNotarization.currencyState.primaryCurrencyOut;
915
136f16ad 916 printf("importedcurrency %s\nspentcurrencyout %s\ngatewaydeposits %s\n",
a36e0d92 917 importedCurrency.ToUniValue().write(1,2).c_str(),
918 spentCurrencyOut.ToUniValue().write(1,2).c_str(),
136f16ad 919 gatewayDeposits.ToUniValue().write(1,2).c_str());
a36e0d92 920
921 gatewayDeposits = (gatewayDeposits - spentCurrencyOut).CanonicalMap();
e6c5e0b8 922
ca768726 923 printf("newNotarization.currencyState %s\nnewgatewaydeposits %s\n",
924 newNotarization.currencyState.ToUniValue().write(1,2).c_str(),
136f16ad 925 gatewayDeposits.ToUniValue().write(1,2).c_str());
e6c5e0b8 926
c31944d3 927 // add the reserve deposit output with all deposits for this currency for the new chain
928 if (gatewayDeposits.valueMap.size())
929 {
930 CCcontract_info *depositCp;
931 CCcontract_info depositCC;
932
933 // create the import thread output
934 depositCp = CCinit(&depositCC, EVAL_RESERVE_DEPOSIT);
faffe06c 935 std::vector<CTxDestination> depositDests({CPubKey(ParseHex(depositCC.CChexstr))});
c31944d3 936 CReserveDeposit rd(newCurID, gatewayDeposits);
937 CAmount nativeOut = gatewayDeposits.valueMap.count(ASSETCHAINS_CHAINID) ? gatewayDeposits.valueMap[ASSETCHAINS_CHAINID] : 0;
938 outputs.push_back(CTxOut(nativeOut, MakeMofNCCScript(CConditionObj<CReserveDeposit>(EVAL_RESERVE_DEPOSIT, depositDests, 1, &rd))));
939 }
940
d5af62fe 941 if (newCurrency.notaries.size())
942 {
943 // notaries all get an even share of 10% of the launch fee in the launch currency to use for notarizing
944 // they may also get pre-allocations
945 uint160 notaryNativeID = ConnectedChains.FirstNotaryChain().chainDefinition.GetID();
946 CAmount notaryFeeShare = ConnectedChains.FirstNotaryChain().chainDefinition.currencyRegistrationFee / 10;
947 additionalFees -= CCurrencyValueMap(std::vector<uint160>({notaryNativeID}), std::vector<int64_t>({notaryFeeShare}));
948 CAmount oneNotaryShare = notaryFeeShare / newCurrency.notaries.size();
949 CAmount notaryModExtra = notaryFeeShare % newCurrency.notaries.size();
950 for (auto &oneNotary : newCurrency.notaries)
951 {
952 CTokenOutput to(notaryNativeID, oneNotaryShare);
953 if (notaryModExtra)
954 {
955 to.reserveValues.valueMap[notaryNativeID]++;
956 notaryModExtra--;
957 }
958 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT,
959 std::vector<CTxDestination>({CIdentityID(oneNotary)}),
960 1,
961 &to))));
962 }
963 }
964
6f40dc90 965 cci.numOutputs = importOutputs.size();
966
967 // now add the import itself
968 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCrossChainImport>(EVAL_CROSSCHAIN_IMPORT, dests, 1, &cci))));
969
970 // add notarization before other outputs
971 cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
972 if (newCurID == ASSETCHAINS_CHAINID &&
973 newCurrency.notarizationProtocol == newCurrency.NOTARIZATION_NOTARY_CHAINID)
974 {
975 dests = std::vector<CTxDestination>({CIdentityID(newCurID)});
976 }
977 else
978 {
979 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
980 }
981 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CPBaaSNotarization>(EVAL_EARNEDNOTARIZATION, dests, 1, &newNotarization))));
982
0b1a0e7f 983 // add export before other outputs
6f40dc90 984 cp = CCinit(&CC, EVAL_NOTARY_EVIDENCE);
985 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
986 // now, we need to put the export evidence, followed by the import outputs
987 CNotaryEvidence evidence = CNotaryEvidence(cci.sourceSystemID,
0b1a0e7f 988 CUTXORef(uint256(), notarizationIdx),
6f40dc90 989 true,
990 std::map<CIdentityID, CIdentitySignature>(),
0b1a0e7f 991 std::vector<CPartialTransactionProof>({pFirstExport->second}),
6f40dc90 992 CNotaryEvidence::TYPE_PARTIAL_TXPROOF);
993 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CNotaryEvidence>(EVAL_NOTARY_EVIDENCE, dests, 1, &evidence))));
994
995 outputs.insert(outputs.end(), importOutputs.begin(), importOutputs.end());
c8c684e9 996 }
997 else
998 {
999 // begin with an empty import for this currency
1000 // create an import based on launch conditions that covers all pre-allocations and uses the initial notarization
2f1f5cda 1001
1002 // if the currency is new and owned by this chain, its registration requires the fee, paid in its launch chain currency
1003 // otherwise, it is being imported from another chain and requires an import fee
1004 CCurrencyValueMap registrationFees;
1005 CAmount registrationAmount = 0;
1006 if (newCurrency.systemID == ASSETCHAINS_CHAINID)
1007 {
1008 if (newCurrency.launchSystemID != ASSETCHAINS_CHAINID)
1009 {
1010 registrationFees = CCurrencyValueMap(std::vector<uint160>({newCurrency.launchSystemID}),
1011 std::vector<int64_t>({ConnectedChains.FirstNotaryChain().chainDefinition.currencyRegistrationFee}));
1012 }
1013 else
1014 {
1015 registrationAmount = ConnectedChains.ThisChain().currencyRegistrationFee;
1016 }
1017 }
1018 else
1019 {
179b6f82 1020 registrationAmount = 0;
2f1f5cda 1021 }
a420f7d8 1022
179b6f82 1023 CCrossChainImport cci = CCrossChainImport(ConnectedChains.ThisChain().launchSystemID,
c8c684e9 1024 1,
1025 newCurID,
1026 CCurrencyValueMap());
203d1021 1027 cci.SetDefinitionImport(true);
c8c684e9 1028 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCrossChainImport>(EVAL_CROSSCHAIN_IMPORT, dests, 1, &cci))));
2f1f5cda 1029
2f1f5cda 1030 // add notarization before other outputs
1031 cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
1032 if (newCurID == ASSETCHAINS_CHAINID &&
1033 newCurrency.notarizationProtocol == newCurrency.NOTARIZATION_NOTARY_CHAINID)
1034 {
1035 dests = std::vector<CTxDestination>({CIdentityID(newCurID)});
1036 }
1037 else
1038 {
1039 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
1040 }
52c4eb12 1041 // this currency is not launching now
1042 newNotarization.SetLaunchConfirmed();
1043 newNotarization.SetLaunchComplete();
37434dab 1044 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CPBaaSNotarization>(EVAL_EARNEDNOTARIZATION, dests, 1, &newNotarization))));
2f1f5cda 1045
1046 CReserveTransactionDescriptor rtxd;
37434dab 1047 CCoinbaseCurrencyState importState = newNotarization.currencyState;
2f1f5cda 1048 importState.RevertReservesAndSupply();
1049 CCurrencyValueMap importedCurrency;
1050 CCurrencyValueMap gatewayDepositsIn;
1051 CCurrencyValueMap spentCurrencyOut;
1052 CCoinbaseCurrencyState newCurrencyState;
1053 if (!rtxd.AddReserveTransferImportOutputs(ConnectedChains.FirstNotaryChain().chainDefinition,
1054 ConnectedChains.ThisChain(),
1055 newCurrency,
1056 importState,
1057 std::vector<CReserveTransfer>(),
1058 outputs,
1059 importedCurrency,
1060 gatewayDepositsIn,
1061 spentCurrencyOut,
1062 &newCurrencyState))
1063 {
1064 LogPrintf("Invalid starting currency import for %s\n", ConnectedChains.ThisChain().name.c_str());
1065 printf("Invalid starting currency import for %s\n", ConnectedChains.ThisChain().name.c_str());
1066 return false;
1067 }
c8c684e9 1068 }
2f1f5cda 1069 // export thread
1070 cp = CCinit(&CC, EVAL_CROSSCHAIN_EXPORT);
1071 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
1072 CCrossChainExport ccx;
1073
1074 ccx = CCrossChainExport(ASSETCHAINS_CHAINID, 1, 1, newCurrency.systemID, newCurID, 0, CCurrencyValueMap(), CCurrencyValueMap(), uint256());
1075 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCrossChainExport>(EVAL_CROSSCHAIN_EXPORT, dests, 1, &ccx))));
c8c684e9 1076 }
1077 else
1078 {
1079 cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
1080 if (newCurID == ASSETCHAINS_CHAINID &&
1081 newCurrency.notarizationProtocol == newCurrency.NOTARIZATION_NOTARY_CHAINID)
1082 {
1083 dests = std::vector<CTxDestination>({CIdentityID(newCurID)});
1084 }
1085 else
1086 {
1087 dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
1088 }
1089 // we notarize our notary chain here, not ourselves
37434dab 1090 if (newNotarization.currencyID == ASSETCHAINS_CHAINID)
c8c684e9 1091 {
37434dab 1092 if (!newNotarization.SetMirror())
a041b57e 1093 {
c8c684e9 1094 LogPrintf("Cannot mirror our notarization from notary chain\n");
1095 printf("Cannot mirror our notarization from notary chain\n");
1096 return false;
a041b57e 1097 }
1098 }
923bb2c0 1099 newNotarization.SetBlockOneNotarization();
37434dab 1100 outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CPBaaSNotarization>(EVAL_EARNEDNOTARIZATION, dests, 1, &newNotarization))));
c8c684e9 1101 }
c8c684e9 1102 return true;
1103}
1104
1105// create all special PBaaS outputs for block 1
1106bool MakeBlockOneCoinbaseOutputs(std::vector<CTxOut> &outputs,
1107 CPBaaSNotarization &launchNotarization,
24d12992 1108 CCurrencyValueMap &additionalFees,
c8c684e9 1109 const Consensus::Params &consensusParams)
1110{
c8c684e9 1111 uint160 thisChainID = ConnectedChains.ThisChain().GetID();
203d1021 1112 CCurrencyDefinition &thisChain = ConnectedChains.ThisChain();
37434dab 1113 uint160 firstNotaryID = ConnectedChains.FirstNotaryChain().GetID();
c8c684e9 1114 CCoinbaseCurrencyState currencyState;
9baf4edc 1115 std::map<uint160, std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>>> blockOneExportImports;
a041b57e 1116
203d1021 1117 std::pair<CUTXORef, CPartialTransactionProof> launchNotarizationProof;
0b1a0e7f 1118 std::pair<CUTXORef, CPartialTransactionProof> launchExportProof;
a36e0d92 1119 std::vector<CReserveTransfer> launchExportTransfers;
e7c64795 1120 CPBaaSNotarization notaryNotarization;
203d1021 1121
1122 if (!GetBlockOneLaunchNotarization(ConnectedChains.FirstNotaryChain(),
1123 thisChainID,
1124 thisChain,
1125 launchNotarization,
e7c64795 1126 notaryNotarization,
0b1a0e7f 1127 launchNotarizationProof,
a36e0d92 1128 launchExportProof,
1129 launchExportTransfers))
c8c684e9 1130 {
1131 // cannot make block 1 unless we can get the initial currency state from the first notary system
1132 LogPrintf("Cannot find chain on notary system\n");
1133 printf("Cannot find chain on notary system\n");
1134 return false;
1135 }
1136
1137 // we need to have a launch decision to be able to mine any blocks, prior to launch being clear,
1138 // it is not an error. we are just not ready.
1139 if (!launchNotarization.IsLaunchCleared())
1140 {
1141 return false;
1142 }
1143
2f1f5cda 1144 if (!launchNotarization.IsLaunchConfirmed())
c8c684e9 1145 {
1146 // we must reach minimums in all currencies to launch
1147 LogPrintf("This chain did not receive the minimum currency contributions and cannot launch. Pre-launch contributions to this chain can be refunded.\n");
1148 printf("This chain did not receive the minimum currency contributions and cannot launch. Pre-launch contributions to this chain can be refunded.\n");
1149 return false;
1150 }
1151
9baf4edc 1152 // get initial imports
5d75d90d 1153 if (!GetBlockOneImports(ConnectedChains.FirstNotaryChain(), launchNotarization, blockOneExportImports))
9baf4edc 1154 {
1155 // we must reach minimums in all currencies to launch
1156 LogPrintf("Cannot retrieve initial export imports from notary system\n");
1157 printf("Cannot retrieve initial export imports from notary system\n");
1158 return false;
1159 }
1160
c8c684e9 1161 // get all currencies/IDs that we will need to retrieve from our notary chain
5d75d90d 1162 std::set<uint160> blockOneCurrencies;
e6c5e0b8 1163 std::set<uint160> blockOneIDs = {ASSETCHAINS_CHAINID};
c8c684e9 1164 std::set<uint160> convertersToCreate;
1165
1166 CPBaaSNotarization converterNotarization;
203d1021 1167 std::pair<CUTXORef, CPartialTransactionProof> converterNotarizationProof;
0b1a0e7f 1168 std::pair<CUTXORef, CPartialTransactionProof> converterExportProof;
a36e0d92 1169 std::vector<CReserveTransfer> converterExportTransfers;
441087ab 1170 uint160 converterCurrencyID = thisChain.GatewayConverterID();
203d1021 1171 CCurrencyDefinition converterCurDef;
c8c684e9 1172
1173 // if we have a converter currency, ensure that it also meets requirements for currency launch
1174 if (!thisChain.gatewayConverterName.empty())
1175 {
1176 if (!GetBlockOneLaunchNotarization(ConnectedChains.FirstNotaryChain(),
203d1021 1177 converterCurrencyID,
1178 converterCurDef,
1179 converterNotarization,
e7c64795 1180 notaryNotarization,
0b1a0e7f 1181 converterNotarizationProof,
a36e0d92 1182 converterExportProof,
1183 converterExportTransfers))
a041b57e 1184 {
c8c684e9 1185 LogPrintf("Unable to get gateway converter initial state\n");
1186 printf("Unable to get gateway converter initial state\n");
1187 return false;
1188 }
a041b57e 1189
54f68f98 1190 notaryNotarization.currencyStates[converterCurrencyID] = converterNotarization.currencyState;
1191
c8c684e9 1192 // both currency and primary gateway must have their pre-launch phase complete before we can make a decision
1193 // about launching
1194 if (!converterNotarization.IsLaunchCleared())
1195 {
1196 return false;
1197 }
a041b57e 1198
c8c684e9 1199 // we need to have a cleared launch to be able to launch
1200 if (!converterNotarization.IsLaunchConfirmed())
1201 {
1202 LogPrintf("Primary currency met requirements for launch, but gateway currency converter did not\n");
1203 printf("Primary currency met requirements for launch, but gateway currency converter did not\n");
1204 return false;
1205 }
a041b57e 1206
c8c684e9 1207 convertersToCreate.insert(converterCurrencyID);
c8c684e9 1208 }
a041b57e 1209
2f1f5cda 1210 // Now, add block 1 imports, which provide a foundation of all IDs and currencies needed to launch the
c8c684e9 1211 // new system, including ID and currency outputs for notary chain, all currencies we accept for pre-conversion,
1212 // native currency of system launching the chain.
c8c684e9 1213 for (auto &oneNotary : ConnectedChains.notarySystems)
1214 {
bea765bd 1215 // first, we need to have the native notary currency itself and its notaries, if it has them
c8c684e9 1216 blockOneCurrencies.insert(oneNotary.first);
e4e650fa 1217 blockOneIDs.insert(oneNotary.second.notaryChain.chainDefinition.notaries.begin(), oneNotary.second.notaryChain.chainDefinition.notaries.end());
c8c684e9 1218 }
a041b57e 1219
8fab3a0d 1220 for (auto &onePrealloc : thisChain.preAllocation)
1221 {
1222 blockOneIDs.insert(onePrealloc.first);
1223 }
1224
bea765bd 1225 // get this chain's notaries
c8c684e9 1226 auto &notaryIDs = ConnectedChains.ThisChain().notaries;
1227 blockOneIDs.insert(notaryIDs.begin(), notaryIDs.end());
1228
1229 // now retrieve IDs and currencies
1230 std::map<uint160, std::pair<CCurrencyDefinition,CPBaaSNotarization>> currencyImports;
1231 std::map<uint160, CIdentity> identityImports;
1232 if (!ConnectedChains.GetNotaryCurrencies(ConnectedChains.FirstNotaryChain(), blockOneCurrencies, currencyImports) ||
1233 !ConnectedChains.GetNotaryIDs(ConnectedChains.FirstNotaryChain(), blockOneIDs, identityImports))
1234 {
1235 // we must reach minimums in all currencies to launch
1236 LogPrintf("Cannot retrieve identity and currency definitions needed to create block 1\n");
1237 printf("Cannot retrieve identity and currency definitions needed to create block 1\n");
1238 return false;
1239 }
1240
e7c64795 1241 if (currencyImports.count(notaryNotarization.currencyID))
1242 {
1243 currencyImports[notaryNotarization.currencyID].second = notaryNotarization;
1244 }
1245
c8c684e9 1246 // add all imported currency and identity outputs, identity revocaton and recovery IDs must be explicitly imported if needed
1247 for (auto &oneIdentity : identityImports)
1248 {
1249 outputs.push_back(CTxOut(0, oneIdentity.second.IdentityUpdateOutputScript(1)));
1250 }
1251
e6c5e0b8 1252 // calculate all issued currency on this chain for both the native and converter currencies,
1253 // which is the only currency that can be considered a gateway deposit at launch. this can
1254 // be used for native currency fee conversions
1255 CCurrencyValueMap gatewayDeposits;
1256
203d1021 1257 bool success = AddOneCurrencyImport(thisChain,
1258 launchNotarization,
1259 &launchNotarizationProof,
0b1a0e7f 1260 &launchExportProof,
a36e0d92 1261 launchExportTransfers,
e6c5e0b8 1262 gatewayDeposits,
24d12992 1263 outputs,
1264 additionalFees);
203d1021 1265
1266 // now, the converter
1267 if (success && converterCurDef.IsValid())
c8c684e9 1268 {
e6c5e0b8 1269 // TODO: add a new ID for the converter currency, controlled by the same primary addresses as the
1270 // ID for this chain
1271 CCurrencyValueMap converterDeposits;
1272
b4ba7e7c 1273 success = AddOneCurrencyImport(converterCurDef,
203d1021 1274 converterNotarization,
1275 &converterNotarizationProof,
0b1a0e7f 1276 &converterExportProof,
a36e0d92 1277 converterExportTransfers,
e6c5e0b8 1278 converterDeposits,
24d12992 1279 outputs,
1280 additionalFees);
203d1021 1281 }
1282
1283 if (success)
1284 {
1285 currencyImports.erase(ASSETCHAINS_CHAINID);
1286 currencyImports.erase(converterCurrencyID);
1287 // now, add the rest of necessary currencies
1288 for (auto &oneCurrency : currencyImports)
c8c684e9 1289 {
203d1021 1290 success = AddOneCurrencyImport(oneCurrency.second.first,
1291 oneCurrency.second.second,
1292 nullptr,
0b1a0e7f 1293 nullptr,
a36e0d92 1294 std::vector<CReserveTransfer>(),
e6c5e0b8 1295 gatewayDeposits,
24d12992 1296 outputs,
1297 additionalFees);
203d1021 1298 if (!success)
1299 {
1300 break;
1301 }
a041b57e 1302 }
1303 }
c8c684e9 1304 return success;
a041b57e 1305}
1306
855714b0 1307CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const std::vector<CTxOut> &minerOutputs, bool isStake)
d247a5d1 1308{
41f170fd
MT
1309 // instead of one scriptPubKeyIn, we take a vector of them along with relative weight. each is assigned a percentage of the block subsidy and
1310 // mining reward based on its weight relative to the total
855714b0 1311 if (!(minerOutputs.size() && ConnectedChains.SetLatestMiningOutputs(minerOutputs) || isStake))
06f41160 1312 {
a4f9bc97 1313 fprintf(stderr,"%s: Must have valid miner outputs, including script with valid PK, PKH, or Verus ID destination.\n", __func__);
88bc6df5 1314 return NULL;
06f41160 1315 }
1316
855714b0 1317 CTxDestination firstDestination;
a4f9bc97 1318
bb6c3482 1319 if (minerOutputs.size())
06f41160 1320 {
bb6c3482 1321 int64_t shareCheck = 0;
855714b0 1322 CTxDestination checkDest;
1323 for (auto &output : minerOutputs)
c3250dcd 1324 {
855714b0 1325 shareCheck += output.nValue;
1326 if (shareCheck < 0 ||
1327 shareCheck > INT_MAX ||
1328 !ExtractDestination(output.scriptPubKey, checkDest) ||
1329 (checkDest.which() == COptCCParams::ADDRTYPE_INVALID))
bb6c3482 1330 {
1331 fprintf(stderr,"Invalid miner outputs share specifications\n");
1332 return NULL;
1333 }
c3250dcd 1334 }
855714b0 1335 ExtractDestination(minerOutputs[0].scriptPubKey, firstDestination);
06f41160 1336 }
1337
855714b0 1338 uint32_t blocktime;
2a6a442a 1339 //fprintf(stderr,"create new block\n");
df756d24 1340 // Create new block
08c58194 1341 std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
d247a5d1 1342 if(!pblocktemplate.get())
1b5b89ba 1343 {
1344 fprintf(stderr,"pblocktemplate.get() failure\n");
d247a5d1 1345 return NULL;
1b5b89ba 1346 }
d247a5d1 1347 CBlock *pblock = &pblocktemplate->block; // pointer for convenience
12217420 1348
855714b0 1349 pblock->nSolution.resize(Eh200_9.SolutionWidth);
1350
12217420 1351 pblock->SetVersionByHeight(chainActive.LastTip()->GetHeight() + 1);
1352
1353 // -regtest only: allow overriding block.nVersion with
dbca89b7 1354 // -blockversion=N to test forking scenarios
793a72e3 1355 if (chainparams.MineBlocksOnDemand())
dbca89b7 1356 pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
e9e70b95 1357
41f170fd 1358 // Add dummy coinbase tx placeholder as first transaction
4949004d 1359 pblock->vtx.push_back(CTransaction());
41f170fd 1360
d247a5d1
JG
1361 pblocktemplate->vTxFees.push_back(-1); // updated at end
1362 pblocktemplate->vTxSigOps.push_back(-1); // updated at end
e9e70b95 1363
d247a5d1 1364 // Largest block you're willing to create:
ad898b40 1365 unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
855714b0 1366
d247a5d1
JG
1367 // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
1368 nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
f711aed7 1369
1370 unsigned int nMaxIDSize = nBlockMaxSize / 2;
1371 unsigned int nCurrentIDSize = 0;
e9e70b95 1372
d247a5d1
JG
1373 // How much of the block should be dedicated to high-priority transactions,
1374 // included regardless of the fees they pay
1375 unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
1376 nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
e9e70b95 1377
d247a5d1
JG
1378 // Minimum block size you want to create; block will be filled with free transactions
1379 // until there are no more or the block reaches this size:
037b4f14 1380 unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE);
d247a5d1 1381 nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
e9e70b95 1382
d247a5d1 1383 // Collect memory pool transactions into the block
a372168e 1384 CAmount nFees = 0;
855714b0 1385 CAmount takenFees = 0;
df756d24 1386
41f170fd 1387 bool isVerusActive = IsVerusActive();
56fe75cb 1388 CCurrencyDefinition &thisChain = ConnectedChains.ThisChain();
56fe75cb 1389
1390 std::vector<CAmount> exchangeRate(thisChain.currencies.size());
41f170fd 1391
df756d24
MT
1392 // we will attempt to spend any cheats we see
1393 CTransaction cheatTx;
1394 boost::optional<CTransaction> cheatSpend;
1395 uint256 cbHash;
1396
562852ab 1397 CBlockIndex* pindexPrev = 0;
fdf05416 1398 bool loop = true;
1399 while (loop)
d247a5d1 1400 {
fdf05416 1401 loop = false;
1402 int nHeight;
df756d24 1403 const Consensus::Params &consensusParams = chainparams.GetConsensus();
fdf05416 1404 uint32_t consensusBranchId;
fdf05416 1405 int64_t nMedianTimePast = 0;
1406 uint32_t proposedTime = 0;
a0dd01bc 1407
a0dd01bc 1408 {
fdf05416 1409 while (proposedTime == nMedianTimePast)
a0dd01bc 1410 {
fdf05416 1411 if (proposedTime)
1412 {
1413 MilliSleep(20);
1414 }
1415 LOCK(cs_main);
1416 pindexPrev = chainActive.LastTip();
1417 nHeight = pindexPrev->GetHeight() + 1;
1418 consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
fdf05416 1419 nMedianTimePast = pindexPrev->GetMedianTimePast();
a0dd01bc 1420 proposedTime = GetAdjustedTime();
fdf05416 1421
a0dd01bc 1422 if (proposedTime == nMedianTimePast)
fdf05416 1423 {
1424 boost::this_thread::interruption_point();
1425 }
a0dd01bc 1426 }
1427 }
fdf05416 1428
a420f7d8 1429 CCoinbaseCurrencyState currencyState;
7c70438d 1430 CCoinsViewCache view(pcoinsTip);
f9155fec 1431 uint32_t expired; uint64_t commission;
6ff77181 1432
4fc309f0 1433 SaplingMerkleTree sapling_tree;
a420f7d8 1434
1435 {
1436 LOCK2(cs_main, mempool.cs);
1437 if (pindexPrev != chainActive.LastTip())
1438 {
1439 // try again
1440 loop = true;
1441 continue;
1442 }
1443 pblock->nTime = GetAdjustedTime();
1444
1445 currencyState = ConnectedChains.GetCurrencyState(nHeight);
1446
1447 if (!(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree)))
1448 {
1449 LogPrintf("%s: failed to get Sapling anchor\n", __func__);
1450 assert(false);
1451 }
1452 }
31a04d28 1453
d247a5d1
JG
1454 // Priority order to process transactions
1455 list<COrphan> vOrphan; // list memory doesn't move
1456 map<uint256, vector<COrphan*> > mapDependers;
1457 bool fPrintPriority = GetBoolArg("-printpriority", false);
e9e70b95 1458
d247a5d1
JG
1459 // This vector will be sorted into a priority queue:
1460 vector<TxPriority> vecPriority;
df756d24
MT
1461 vecPriority.reserve(mempool.mapTx.size() + 1);
1462
df756d24 1463 {
a420f7d8 1464 LOCK(cs_main);
1465
1466 // check if we should add cheat transaction
1467 CBlockIndex *ppast;
1468 CTransaction cb;
1469 int cheatHeight = nHeight - COINBASE_MATURITY < 1 ? 1 : nHeight - COINBASE_MATURITY;
1470 if (defaultSaplingDest &&
1471 chainActive.Height() > 100 &&
1472 (ppast = chainActive[cheatHeight]) &&
1473 ppast->IsVerusPOSBlock() &&
1474 cheatList.IsHeightOrGreaterInList(cheatHeight))
df756d24 1475 {
a420f7d8 1476 // get the block and see if there is a cheat candidate for the stake tx
1477 CBlock b;
1478 if (!(fHavePruned && !(ppast->nStatus & BLOCK_HAVE_DATA) && ppast->nTx > 0) && ReadBlockFromDisk(b, ppast, chainparams.GetConsensus(), 1))
df756d24 1479 {
a420f7d8 1480 CTransaction &stakeTx = b.vtx[b.vtx.size() - 1];
df756d24 1481
a420f7d8 1482 if (cheatList.IsCheatInList(stakeTx, &cheatTx))
73a4cd20 1483 {
a420f7d8 1484 // make and sign the cheat transaction to spend the coinbase to our address
1485 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
df756d24 1486
a420f7d8 1487 uint32_t voutNum;
1488 // get the first vout with value
1489 for (voutNum = 0; voutNum < b.vtx[0].vout.size(); voutNum++)
df756d24 1490 {
a420f7d8 1491 if (b.vtx[0].vout[voutNum].nValue > 0)
1492 break;
df756d24
MT
1493 }
1494
a420f7d8 1495 // send to the same pub key as the destination of this block reward
1496 if (MakeCheatEvidence(mtx, b.vtx[0], voutNum, cheatTx))
df756d24 1497 {
a420f7d8 1498 LOCK(pwalletMain->cs_wallet);
1499 TransactionBuilder tb = TransactionBuilder(consensusParams, nHeight);
1500 cb = b.vtx[0];
1501 cbHash = cb.GetHash();
1502
1503 bool hasInput = false;
1504 for (uint32_t i = 0; i < cb.vout.size(); i++)
1505 {
1506 // add the spends with the cheat
1507 if (cb.vout[i].nValue > 0)
88d014d0 1508 {
a420f7d8 1509 tb.AddTransparentInput(COutPoint(cbHash,i), cb.vout[0].scriptPubKey, cb.vout[0].nValue);
1510 hasInput = true;
88d014d0 1511 }
a420f7d8 1512 }
1513
1514 if (hasInput)
1515 {
1516 // this is a send from a t-address to a sapling address, which we don't have an ovk for.
1517 // Instead, generate a common one from the HD seed. This ensures the data is
1518 // recoverable, at least for us, while keeping it logically separate from the ZIP 32
1519 // Sapling key hierarchy, which the user might not be using.
1520 uint256 ovk;
1521 HDSeed seed;
1522 if (pwalletMain->GetHDSeed(seed)) {
1523 ovk = ovkForShieldingFromTaddr(seed);
1524
1525 // send everything to Sapling address
1526 tb.SendChangeTo(defaultSaplingDest.value(), ovk);
1527
1528 tb.AddOpRet(mtx.vout[mtx.vout.size() - 1].scriptPubKey);
1529
1530 TransactionBuilderResult buildResult(tb.Build());
1531 if (!buildResult.IsError() && buildResult.IsTx())
1532 {
1533 cheatSpend = buildResult.GetTxOrThrow();
1534 }
1535 else
1536 {
1537 LogPrintf("Error building cheat catcher transaction: %s\n", buildResult.GetError().c_str());
1538 }
88d014d0 1539 }
df756d24
MT
1540 }
1541 }
1542 }
1543 }
1544 }
df756d24 1545
a420f7d8 1546 if (cheatSpend)
45bb4681 1547 {
a420f7d8 1548 LOCK(mempool.cs);
1549
1550 cheatTx = cheatSpend.value();
1551 std::list<CTransaction> removed;
1552 mempool.removeConflicts(cheatTx, removed);
1553 printf("Found cheating stake! Adding cheat spend for %.8f at block #%d, coinbase tx\n%s\n",
1554 (double)cb.GetValueOut() / (double)COIN, nHeight, cheatSpend.value().vin[0].prevout.hash.GetHex().c_str());
1555
1556 // add to mem pool and relay
1557 if (myAddtomempool(cheatTx))
1558 {
1559 RelayTransaction(cheatTx);
1560 }
45bb4681 1561 }
271326fa 1562 }
1563
41f170fd
MT
1564 //
1565 // Now start solving the block
1566 //
1567
1568 uint64_t nBlockSize = 1000; // initial size
1569 uint64_t nBlockTx = 1; // number of transactions - always have a coinbase
1570 uint32_t autoTxSize = 0; // extra transaction overhead that we will add while creating the block
1571 int nBlockSigOps = 100;
1572
1573 // VerusPoP staking transaction data
1574 CMutableTransaction txStaked; // if this is a stake operation, the staking transaction that goes at the end
1575 uint32_t nStakeTxSize = 0; // serialized size of the stake transaction
1576
855714b0 1577 // if this is not for mining, first determine if we have a right to make a block
41f170fd
MT
1578 if (isStake)
1579 {
b2a59a12 1580 uint64_t txfees, utxovalue;
1581 uint32_t txtime;
1582 uint256 utxotxid;
1583 int32_t i, siglen, numsigs, utxovout;
1584 std::vector<unsigned char> utxosig;
1585
41f170fd
MT
1586 txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight);
1587
41f170fd
MT
1588 if (ASSETCHAINS_LWMAPOS != 0)
1589 {
1590 uint32_t nBitsPOS;
1591 arith_uint256 posHash;
1592
855714b0 1593 siglen = verus_staked(pblock, txStaked, nBitsPOS, posHash, utxosig, firstDestination);
41f170fd 1594 blocktime = GetAdjustedTime();
41f170fd 1595 }
41f170fd
MT
1596
1597 if (siglen <= 0)
1598 {
1599 return NULL;
1600 }
1601
1602 pblock->nTime = blocktime;
1603 nStakeTxSize = GetSerializeSize(txStaked, SER_NETWORK, PROTOCOL_VERSION);
1604 nBlockSize += nStakeTxSize;
1605 }
1606
bb6c3482 1607 ConnectedChains.AggregateChainTransfers(firstDestination, nHeight);
1608
41f170fd
MT
1609 // Now the coinbase -
1610 // A PBaaS coinbase must have some additional outputs to enable certain chain state and functions to be properly
1611 // validated. All but currency state and the first chain definition are either optional or not valid on non-fractional reserve PBaaS blockchains
1612 // All of these are instant spend outputs that have no maturity wait time and may be spent in the same block.
1613 //
1614 // 1. (required) currency state - current state of currency supply and optionally reserve, premine, etc. This is primarily a data output to provide
1615 // cross check for coin minting and burning operations, making it efficient to determine up-to-date supply, reserves, and conversions. To provide
1616 // an extra level of supply cross-checking and fast data retrieval, this is part of all PBaaS chains' protocol, not just reserves.
1617 // This output also includes reserve and native amounts for total conversions, less fees, of any conversions between Verus reserve and the
1618 // native currency.
1619 //
1620 // 2. (block 1 required) chain definition - in order to confirm the amount of coins converted and issued within the possible range, before chain start,
1621 // new PBaaS chains have a zero-amount, unspendable chain definition output.
1622 //
1623 // 3. (block 1 optional) initial import utxo - for any chain with conversion or pre-conversion, the first coinbase must include an initial import utxo.
1624 // Pre-conversions are handled on the launch chain before the PBaaS chain starts, so they are an additional output, which begins
1625 // as a fixed amount and is spent with as many outputs as necessary to the recipients of the pre-conversion transactions when those pre-conversions
1626 // are imported. All pre-converted outputs get their source currency from a thread that starts with this output in block 1.
1627 //
1628 // 4. (block 1 optional) initial export utxo - reserve chains, or any chain that will use exports to another chain must have an initial export utxo, any chain
1629 // may have one, but currently, they can only be spent with valid exports, which only occur on reserve chains
1630 //
1631 // 5. (optional) notarization output - in order to ensure that notarization can occur independent of the availability of fungible
1632 // coins on the network, and also that the notarization can provide a spendable finalization output and possible reward
1633 //
1634 // In addition, each PBaaS block can be mined with optional, fee-generating transactions. Inporting transactions from the reserve chain or sending
1635 // exported transactions to the reserve chain are optional fee-generating steps that would be easy to do when running multiple daemons.
1636 // The types of transactions miners/stakers may facilitate or create for fees are as follows:
1637 //
1638 // 1. Earned notarization of Verus chain - spends the notarization instant out. must be present and spend the notarization output if there is a notarization output
1639 //
1640 // 2. Imported transactions from the export thread for this PBaaS chain on the Verus blockchain - imported transactions must spend the import utxo
1641 // thread, represent the export from the alternate chain which spends the export output from the prior import transaction, carry a notary proof, and
1642 // include outputs that map to each of its inputs on the source chain. Outputs can include unconverted reserve outputs only on fractional
1643 // reserve chains, pre-converted outputs for any chain with launch conversion, and post launch outputs to be converted on fractional reserve
1644 // chains. Each are handled in the following way:
1645 // a. Unconverted outputs are left as outputs to the intended destination of Verus reserve token and do not pass through the coinbase
1646 // b. Pre-converted outputs require that the import transaction spend the last pre-conversion output starting at block 1 as the source for
1647 // pre-converted currency.
1648 //
1649 // 3. Zero or more aggregated exports that combine individual cross-chain transactions and reserve transfer outputs for export to the Verus chain.
1650 //
1651 // 4. Conversion distribution transactions for all native and reserve currency conversions, including reserve transfer outputs without conversion as
1652 // a second step for reserve transfers that have conversion included. Any remaining pre-converted reserve must always remain in a change output
1653 // until it is exhausted
24d12992 1654 CTxOut premineOut;
41f170fd
MT
1655
1656 // size of conversion tx
0574c740 1657 std::vector<CInputDescriptor> conversionInputs;
41f170fd 1658
4fa3b13d 1659 // if we are a PBaaS chain, first make sure we don't start prematurely, and if
68b309c0 1660 // we should make an earned notarization, make it and set index to non-zero value
41f170fd
MT
1661 int32_t notarizationTxIndex = 0; // index of notarization if it is added
1662 int32_t conversionTxIndex = 0; // index of conversion transaction if it is added
1663
1664 // export transactions can be created here by aggregating all pending transfer requests and either getting 10 or more together, or
1665 // waiting n (10) blocks since the last one. each export must spend the output of the one before it
1666 std::vector<CMutableTransaction> exportTransactions;
1667
1668 // all transaction outputs requesting conversion to another currency (PBaaS fractional reserve only)
1669 // these will be used to calculate conversion price, fees, and generate coinbase conversion output as well as the
1670 // conversion output transaction
1671 std::vector<CTxOut> reserveConversionTo;
1672 std::vector<CTxOut> reserveConversionFrom;
1673
68b309c0 1674 int64_t pbaasTransparentIn = 0;
eb0a6550 1675 int64_t pbaasTransparentOut = 0;
31609f35 1676 //extern int64_t ASSETCHAINS_SUPPLY;
1677 //printf("%lu premine\n", ASSETCHAINS_SUPPLY);
1fa4454d 1678 int64_t blockSubsidy = GetBlockSubsidy(nHeight, consensusParams);
ebee7b5b 1679
56fe75cb 1680 uint160 thisChainID = ConnectedChains.ThisChain().GetID();
41f170fd 1681
8577896f 1682 uint256 mmrRoot;
13ed2980 1683 vector<CInputDescriptor> notarizationInputs;
1fa4454d 1684
41f170fd
MT
1685 // used as scratch for making CCs, should be reinitialized each time
1686 CCcontract_info CC;
1687 CCcontract_info *cp;
c8c684e9 1688 std::vector<CTxDestination> dests;
c3250dcd 1689 CPubKey pkCC;
41f170fd
MT
1690
1691 // Create coinbase tx and set up the null input with height
1692 CMutableTransaction coinbaseTx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
bb6c3482 1693 coinbaseTx.vin.push_back(CTxIn(uint256(), (uint32_t)-1, CScript() << nHeight << OP_0));
41f170fd 1694
41f170fd
MT
1695 // we will update amounts and fees later, but convert the guarded output now for validity checking and size estimate
1696 if (isStake)
1697 {
1698 // if there is a specific destination, use it
1699 CTransaction stakeTx(txStaked);
1700 CStakeParams p;
1701 if (ValidateStakeTransaction(stakeTx, p, false))
1702 {
56fe75cb 1703 if (p.Version() < p.VERSION_EXTENDED_STAKE && !p.pk.IsValid())
41f170fd
MT
1704 {
1705 LogPrintf("CreateNewBlock: invalid public key\n");
1706 fprintf(stderr,"CreateNewBlock: invalid public key\n");
1707 return NULL;
1708 }
c52bd43c 1709 CTxDestination guardedOutputDest = (p.Version() < p.VERSION_EXTENDED_STAKE) ? p.pk : p.delegate;
56fe75cb 1710 coinbaseTx.vout.push_back(CTxOut(1, CScript()));
c52bd43c 1711 if (!MakeGuardedOutput(1, guardedOutputDest, stakeTx, coinbaseTx.vout.back()))
41f170fd 1712 {
56fe75cb 1713 LogPrintf("CreateNewBlock: failed to make GuardedOutput on staking coinbase\n");
1714 fprintf(stderr,"CreateNewBlock: failed to make GuardedOutput on staking coinbase\n");
1715 return NULL;
41f170fd 1716 }
5d6bdede 1717 COptCCParams optP;
5c7c7edc 1718 if (!coinbaseTx.vout.back().scriptPubKey.IsPayToCryptoCondition(optP) || !optP.IsValid())
5d6bdede 1719 {
c52bd43c 1720 MakeGuardedOutput(1, guardedOutputDest, stakeTx, coinbaseTx.vout.back());
5d6bdede 1721 LogPrintf("%s: created invalid staking coinbase\n", __func__);
1722 fprintf(stderr,"%s: created invalid staking coinbase\n", __func__);
1723 return NULL;
1724 }
41f170fd
MT
1725 }
1726 else
1727 {
1728 LogPrintf("CreateNewBlock: invalid stake transaction\n");
1729 fprintf(stderr,"CreateNewBlock: invalid stake transaction\n");
1730 return NULL;
1731 }
1732 }
56fe75cb 1733 else
1734 {
1735 // default outputs for mining and before stake guard or fee calculation
1736 // store the relative weight in the amount output to convert later to a relative portion
1737 // of the reward + fees
855714b0 1738 coinbaseTx.vout.insert(coinbaseTx.vout.end(), minerOutputs.begin(), minerOutputs.end());
56fe75cb 1739 }
41f170fd 1740
34d1aa13 1741 CAmount totalEmission = blockSubsidy;
24d12992 1742 CCurrencyValueMap additionalFees;
34d1aa13 1743
c8c684e9 1744 // if we don't have a connected root PBaaS chain, we can't properly check
1745 // and notarize the start block, so we have to pass the notarization and cross chain steps
67dceeec 1746 bool notaryConnected = ConnectedChains.IsNotaryAvailable();
5cd8b21a 1747
c8c684e9 1748 // at block 1 for a PBaaS chain, we validate launch conditions
1749 if (!isVerusActive && nHeight == 1)
1750 {
1751 CPBaaSNotarization launchNotarization;
e54d0c10 1752 if (!ConnectedChains.readyToStart &&
1753 !ConnectedChains.CheckVerusPBaaSAvailable() &&
1754 !ConnectedChains.readyToStart)
76f69285 1755 {
1756 return NULL;
1757 }
24d12992 1758 if (!MakeBlockOneCoinbaseOutputs(coinbaseTx.vout, launchNotarization, additionalFees, Params().GetConsensus()))
4fa3b13d 1759 {
c8c684e9 1760 // can't mine block 1 if we are not connected to a notary
1761 printf("%s: cannot create block one coinbase outputs\n", __func__);
1762 LogPrintf("%s: cannot create block one coinbase outputs\n", __func__);
c8c684e9 1763 return NULL;
989b1de1 1764 }
c8c684e9 1765 currencyState = launchNotarization.currencyState;
1766 }
989b1de1 1767
9abe77b7 1768 // if we are a notary, notarize
67953607 1769 if (nHeight > CPBaaSNotarization::MIN_BLOCKS_BEFORE_NOTARY_FINALIZED && !VERUS_NOTARYID.IsNull())
9abe77b7 1770 {
1771 CValidationState state;
d5af62fe 1772 TransactionBuilder notarizationBuilder = TransactionBuilder(consensusParams, nHeight, pwalletMain);
9abe77b7 1773 bool finalized;
a420f7d8 1774 CTransaction notarizationTx;
9abe77b7 1775 if (CPBaaSNotarization::ConfirmOrRejectNotarizations(pwalletMain, ConnectedChains.FirstNotaryChain(), state, notarizationBuilder, finalized))
1776 {
d5af62fe 1777 if (!notarizationBuilder.mtx.vin.size())
48ccc7f5 1778 {
544b1140 1779 bool success = false;
1780 CCurrencyValueMap reserveValueOut;
1781 CAmount nativeValueOut;
d5af62fe 1782 // get a native currency input capable of paying a fee, and make our notary ID the change address
1783 std::set<std::pair<const CWalletTx *, unsigned int>> setCoinsRet;
1784 {
584ea569 1785 LOCK2(cs_main, pwalletMain->cs_wallet);
d5af62fe 1786 std::vector<COutput> vCoins;
d5af62fe 1787 if (IsVerusActive())
1788 {
1789 pwalletMain->AvailableCoins(vCoins,
1790 false,
1791 nullptr,
1792 false,
1793 true,
1794 true,
1795 true,
1796 false);
544b1140 1797 success = pwalletMain->SelectCoinsMinConf(CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE, 0, 0, vCoins, setCoinsRet, nativeValueOut);
d5af62fe 1798 notarizationBuilder.SetFee(CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE);
1799 }
1800 else
1801 {
1802 CCurrencyValueMap totalTxFees;
1803 totalTxFees.valueMap[ConnectedChains.FirstNotaryChain().chainDefinition.GetID()] = CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE;
1804 notarizationBuilder.SetReserveFee(totalTxFees);
1805 notarizationBuilder.SetFee(0);
1806 pwalletMain->AvailableReserveCoins(vCoins,
1807 false,
1808 nullptr,
1809 true,
1810 true,
1811 nullptr,
1812 &totalTxFees,
1813 false);
544b1140 1814
1815 success = pwalletMain->SelectReserveCoinsMinConf(totalTxFees,
1816 0,
1817 0,
1818 1,
1819 vCoins,
1820 setCoinsRet,
1821 reserveValueOut,
1822 nativeValueOut);
d5af62fe 1823 }
1824 }
1825 for (auto &oneInput : setCoinsRet)
1826 {
1827 notarizationBuilder.AddTransparentInput(COutPoint(oneInput.first->GetHash(), oneInput.second),
1828 oneInput.first->vout[oneInput.second].scriptPubKey,
1829 oneInput.first->vout[oneInput.second].nValue);
1830 }
1831 notarizationBuilder.SendChangeTo(CTxDestination(VERUS_NOTARYID));
48ccc7f5 1832 }
d5af62fe 1833 else
48ccc7f5 1834 {
d5af62fe 1835 notarizationBuilder.SetFee(0);
48ccc7f5 1836 }
48ccc7f5 1837
5e34790a 1838 if (notarizationBuilder.mtx.vin.size())
a420f7d8 1839 {
5e34790a 1840 LOCK2(cs_main, mempool.cs);
1841 TransactionBuilderResult buildResult = notarizationBuilder.Build();
1842 if (buildResult.IsTx())
1843 {
1844 notarizationTx = buildResult.GetTxOrThrow();
6c93e6f8 1845
5e34790a 1846 UniValue jsonNotaryConfirmations(UniValue::VOBJ);
1847 TxToUniv(notarizationTx, uint256(), jsonNotaryConfirmations);
1848 //printf("%s: (PII) Submitting notarization confirmations:\n%s\n", __func__, jsonNotaryConfirmations.write(1,2).c_str());
1849 LogPrintf("%s: (PII) Submitting notarization confirmations:\n%s\n", __func__, jsonNotaryConfirmations.write(1,2).c_str());
9abe77b7 1850
5e34790a 1851 // add to mem pool and relay
1852 if (myAddtomempool(notarizationTx))
1853 {
1854 RelayTransaction(notarizationTx);
1855 }
1856 }
1857 else
a420f7d8 1858 {
5e34790a 1859 printf("%s: (PII) error adding notary evidence: %s\n", __func__, buildResult.GetError().c_str());
1860 LogPrintf("%s: (PII) error adding notary evidence: %s\n", __func__, buildResult.GetError().c_str());
a420f7d8 1861 }
1862 }
9abe77b7 1863 }
1864 }
1865
c8c684e9 1866 if (notaryConnected)
1867 {
1868 // if we should make an earned notarization, do so
ac07d7a9 1869 if (nHeight != 1 && !(VERUS_NOTARYID.IsNull() && VERUS_DEFAULTID.IsNull() && VERUS_NODEID.IsNull()))
4fa3b13d 1870 {
ac07d7a9 1871 CIdentityID proposer = VERUS_NOTARYID.IsNull() ? (VERUS_DEFAULTID.IsNull() ? VERUS_NODEID : VERUS_DEFAULTID) : VERUS_NOTARYID;
c8c684e9 1872
41f170fd 1873 // if we have access to our notary daemon
56fe75cb 1874 // create a notarization if we would qualify to do so. add it to the mempool and next block
4fa3b13d 1875 ChainMerkleMountainView mmv = chainActive.GetMMV();
8577896f 1876 mmrRoot = mmv.GetRoot();
1fa4454d
MT
1877 int32_t confirmedInput = -1;
1878 CTxDestination confirmedDest;
c8c684e9 1879 CValidationState state;
1880 CPBaaSNotarization earnedNotarization;
1881
1882 if (CPBaaSNotarization::CreateEarnedNotarization(ConnectedChains.FirstNotaryChain(),
1883 DestinationToTransferDestination(proposer),
1884 state,
1885 coinbaseTx.vout,
1886 earnedNotarization))
4fa3b13d 1887 {
833b3007 1888 }
c8c684e9 1889 CPBaaSNotarization lastImportNotarization;
1890 CUTXORef lastImportNotarizationUTXO;
9abe77b7 1891
1892 CPBaaSNotarization::SubmitFinalizedNotarizations(ConnectedChains.FirstNotaryChain(), state);
c8c684e9 1893 ProcessNewImports(ConnectedChains.FirstNotaryChain().chainDefinition.GetID(), lastImportNotarization, lastImportNotarizationUTXO, nHeight);
4fa3b13d 1894 }
2299bd95 1895 }
855714b0 1896
a420f7d8 1897 // done calling out, take locks for the rest
1898 LOCK2(cs_main, mempool.cs);
1899
c8c684e9 1900 totalEmission = GetBlockSubsidy(nHeight, consensusParams);
1901 blockSubsidy = totalEmission;
24d12992 1902
1903 // PBaaS chain's block 1 currency state is done by the time we get here,
1904 // including pre-allocations, etc.
1905 if (isVerusActive || nHeight != 1)
1906 {
1907 currencyState.UpdateWithEmission(totalEmission);
1908 }
c8c684e9 1909
1910 // process any imports from the current chain to itself
1911 ConnectedChains.ProcessLocalImports();
855714b0 1912
1913 CFeePool feePool;
c8c684e9 1914 if (!CFeePool::GetCoinbaseFeePool(feePool, nHeight - 1) ||
855714b0 1915 (!feePool.IsValid() && CConstVerusSolutionVector::GetVersionByHeight(nHeight - 1) >= CActivationHeight::ACTIVATE_PBAAS))
1916 {
1917 // we should be able to get a valid currency state, if not, fail
1918 LogPrintf("Failure to get fee pool information for blockchain height #%d\n", nHeight - 1);
1919 printf("Failure to get fee pool information for blockchain height #%d\n", nHeight - 1);
1920 return NULL;
34d1aa13 1921 }
e7e14f44 1922
855714b0 1923 uint32_t solutionVersion = CConstVerusSolutionVector::GetVersionByHeight(nHeight);
1924 if (solutionVersion >= CActivationHeight::ACTIVATE_PBAAS && !feePool.IsValid())
1925 {
1926 // first block with a fee pool, so make it valid and empty
1927 feePool = CFeePool();
1928 }
a041b57e 1929
c8c684e9 1930 // coinbase should have all necessary outputs
41f170fd
MT
1931 uint32_t nCoinbaseSize = GetSerializeSize(coinbaseTx, SER_NETWORK, PROTOCOL_VERSION);
1932 nBlockSize += nCoinbaseSize;
e7c700b5 1933
41f170fd
MT
1934 // now create the priority array, including market order reserve transactions, since they can always execute, leave limits for later
1935 bool haveReserveTransactions = false;
1936 uint32_t reserveExchangeLimitSize = 0;
56fe75cb 1937 std::vector<CReserveTransactionDescriptor> limitOrders;
2299bd95 1938
41f170fd 1939 // now add transactions from the mem pool to the priority heap
e328fa32 1940 for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
4d707d51 1941 mi != mempool.mapTx.end(); ++mi)
d247a5d1 1942 {
e328fa32 1943 const CTransaction& tx = mi->GetTx();
41f170fd 1944 uint256 hash = tx.GetHash();
e9e70b95 1945
a1d3c6fb 1946 int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
e9e70b95 1947 ? nMedianTimePast
1948 : pblock->GetBlockTime();
9c034267 1949
9bb37bf0 1950 if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
61f8caf2 1951 {
51376f3c 1952 //fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
14aa6cc0 1953 continue;
61f8caf2 1954 }
9c034267 1955
161f617d 1956 if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 )
6ff77181 1957 {
64b45b71 1958 //fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime);
d247a5d1 1959 continue;
14aa6cc0 1960 }
df756d24 1961
d247a5d1
JG
1962 COrphan* porphan = NULL;
1963 double dPriority = 0;
a372168e 1964 CAmount nTotalIn = 0;
56fe75cb 1965 CCurrencyValueMap totalReserveIn;
d247a5d1 1966 bool fMissingInputs = false;
41f170fd
MT
1967 CReserveTransactionDescriptor rtxd;
1968 bool isReserve = mempool.IsKnownReserveTransaction(hash, rtxd);
e7e14f44 1969
0cb91a8d 1970 if (tx.IsCoinImport())
d247a5d1 1971 {
0cb91a8d
SS
1972 CAmount nValueIn = GetCoinImportValue(tx);
1973 nTotalIn += nValueIn;
1974 dPriority += (double)nValueIn * 1000; // flat multiplier
1975 } else {
41f170fd
MT
1976 if (isReserve)
1977 {
1978 nTotalIn += rtxd.nativeIn;
24d12992 1979 totalReserveIn = rtxd.ReserveInputMap();
1980 assert(!totalReserveIn.valueMap.count(ASSETCHAINS_CHAINID));
f711aed7 1981 if (rtxd.IsIdentity() && CNameReservation(tx).IsValid())
1982 {
1983 nCurrentIDSize += GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
1984 if (nCurrentIDSize > nMaxIDSize)
1985 {
1986 continue;
1987 }
1988 }
41f170fd 1989 }
0cb91a8d 1990 BOOST_FOREACH(const CTxIn& txin, tx.vin)
d247a5d1 1991 {
56fe75cb 1992 CAmount nValueIn = 0;
1993 CCurrencyValueMap reserveValueIn;
41f170fd 1994
0cb91a8d
SS
1995 // Read prev transaction
1996 if (!view.HaveCoins(txin.prevout.hash))
d247a5d1 1997 {
0cb91a8d
SS
1998 // This should never happen; all transactions in the memory
1999 // pool should connect to either transactions in the chain
2000 // or other transactions in the memory pool.
2001 if (!mempool.mapTx.count(txin.prevout.hash))
2002 {
2003 LogPrintf("ERROR: mempool transaction missing input\n");
2004 if (fDebug) assert("mempool transaction missing input" == 0);
2005 fMissingInputs = true;
2006 if (porphan)
2007 vOrphan.pop_back();
2008 break;
2009 }
2010
2011 // Has to wait for dependencies
2012 if (!porphan)
2013 {
2014 // Use list for automatic deletion
2015 vOrphan.push_back(COrphan(&tx));
2016 porphan = &vOrphan.back();
2017 }
2018 mapDependers[txin.prevout.hash].push_back(porphan);
2019 porphan->setDependsOn.insert(txin.prevout.hash);
e7e14f44
MT
2020
2021 const CTransaction &otx = mempool.mapTx.find(txin.prevout.hash)->GetTx();
e7e14f44 2022 // consider reserve outputs and set priority according to their value here as well
56fe75cb 2023 if (isReserve)
e7e14f44 2024 {
56fe75cb 2025 totalReserveIn += otx.vout[txin.prevout.n].ReserveOutValue();
e7e14f44 2026 }
56fe75cb 2027 nTotalIn += otx.vout[txin.prevout.n].nValue;
0cb91a8d 2028 continue;
d247a5d1 2029 }
0cb91a8d
SS
2030 const CCoins* coins = view.AccessCoins(txin.prevout.hash);
2031 assert(coins);
2032
41f170fd 2033 if (isReserve)
e7e14f44 2034 {
56fe75cb 2035 reserveValueIn = coins->vout[txin.prevout.n].ReserveOutValue();
e7e14f44 2036 }
0cb91a8d 2037
41f170fd 2038 nValueIn = coins->vout[txin.prevout.n].nValue;
0cb91a8d
SS
2039 int nConf = nHeight - coins->nHeight;
2040
56fe75cb 2041 dPriority += ((double)((reserveValueIn.valueMap.size() ? currencyState.ReserveToNative(reserveValueIn) : 0) + nValueIn)) * nConf;
71a3314d 2042
71a3314d 2043 if (!isReserve)
2044 {
2045 nTotalIn += nValueIn;
56fe75cb 2046 totalReserveIn += reserveValueIn;
71a3314d 2047 }
d247a5d1 2048 }
9feb4b9e 2049 nTotalIn += tx.GetShieldedValueIn();
d247a5d1 2050 }
0cb91a8d 2051
d247a5d1 2052 if (fMissingInputs) continue;
e9e70b95 2053
d6eb2599 2054 // Priority is sum(valuein * age) / modified_txsize
d247a5d1 2055 unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
4d707d51 2056 dPriority = tx.ComputePriority(dPriority, nTxSize);
e9e70b95 2057
56fe75cb 2058 CAmount nDeltaValueIn = nTotalIn + (totalReserveIn.valueMap.size() ? currencyState.ReserveToNative(totalReserveIn) : 0);
41f170fd
MT
2059 CAmount nFeeValueIn = nDeltaValueIn;
2060 mempool.ApplyDeltas(hash, dPriority, nDeltaValueIn);
e7e14f44 2061
71a3314d 2062 CAmount nativeEquivalentOut = 0;
e7e14f44
MT
2063
2064 // if there is reserve in, or this is a reserveexchange transaction, calculate fee properly
56fe75cb 2065 if (isReserve && rtxd.ReserveOutputMap().valueMap.size())
e7e14f44
MT
2066 {
2067 // if this has reserve currency out, convert it to native currency for fee calculation
56fe75cb 2068 nativeEquivalentOut = currencyState.ReserveToNative(rtxd.ReserveOutputMap());
e7e14f44
MT
2069 }
2070
56fe75cb 2071 CFeeRate feeRate(isReserve ? rtxd.AllFeesAsNative(currencyState) + currencyState.ReserveToNative(rtxd.ReserveConversionFeesMap()) + rtxd.nativeConversionFees :
2072 nFeeValueIn - (tx.GetValueOut() + nativeEquivalentOut), nTxSize);
e7e14f44 2073
d247a5d1
JG
2074 if (porphan)
2075 {
2076 porphan->dPriority = dPriority;
c6cb21d1 2077 porphan->feeRate = feeRate;
d247a5d1
JG
2078 }
2079 else
e328fa32 2080 vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
d247a5d1 2081 }
df756d24 2082
41f170fd
MT
2083 //
2084 // NOW -- REALLY START TO FILL THE BLOCK
bb6c3482 2085 //
41f170fd 2086 // estimate number of conversions, staking transaction size, and additional coinbase outputs that will be required
e7c700b5 2087
41f170fd 2088 int32_t maxPreLimitOrderBlockSize = nBlockMaxSize - std::min(nBlockMaxSize >> 2, reserveExchangeLimitSize);
e7e14f44 2089
355ca565 2090 int64_t interest;
d247a5d1 2091 bool fSortedByFee = (nBlockPrioritySize <= 0);
41f170fd 2092
d247a5d1
JG
2093 TxPriorityCompare comparer(fSortedByFee);
2094 std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
41f170fd
MT
2095
2096 std::vector<int> reservePositions;
2097
2098 // now loop and fill the block, leaving space for reserve exchange limit transactions
d247a5d1
JG
2099 while (!vecPriority.empty())
2100 {
2101 // Take highest priority transaction off the priority queue:
2102 double dPriority = vecPriority.front().get<0>();
c6cb21d1 2103 CFeeRate feeRate = vecPriority.front().get<1>();
4d707d51 2104 const CTransaction& tx = *(vecPriority.front().get<2>());
e9e70b95 2105
d247a5d1
JG
2106 std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
2107 vecPriority.pop_back();
e9e70b95 2108
d247a5d1
JG
2109 // Size limits
2110 unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
41f170fd 2111 if (nBlockSize + nTxSize >= maxPreLimitOrderBlockSize - autoTxSize) // room for extra autotx
61f8caf2 2112 {
41f170fd 2113 //fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d maxPreLimitOrderBlockSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)maxPreLimitOrderBlockSize);
d247a5d1 2114 continue;
61f8caf2 2115 }
e9e70b95 2116
d247a5d1
JG
2117 // Legacy limits on sigOps:
2118 unsigned int nTxSigOps = GetLegacySigOpCount(tx);
a4a40a38 2119 if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
61f8caf2 2120 {
51376f3c 2121 //fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
d247a5d1 2122 continue;
61f8caf2 2123 }
d247a5d1 2124 // Skip free transactions if we're past the minimum block size:
805344dc 2125 const uint256& hash = tx.GetHash();
2a72d459 2126 double dPriorityDelta = 0;
a372168e 2127 CAmount nFeeDelta = 0;
2a72d459 2128 mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
13fc83c7 2129 if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
61f8caf2 2130 {
51376f3c 2131 //fprintf(stderr,"fee rate skip\n");
d247a5d1 2132 continue;
61f8caf2 2133 }
41f170fd 2134
2a72d459 2135 // Prioritise by fee once past the priority size or we run out of high-priority
d247a5d1
JG
2136 // transactions:
2137 if (!fSortedByFee &&
2138 ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
2139 {
2140 fSortedByFee = true;
2141 comparer = TxPriorityCompare(fSortedByFee);
2142 std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
2143 }
e9e70b95 2144
d247a5d1 2145 if (!view.HaveInputs(tx))
61f8caf2 2146 {
51376f3c 2147 //fprintf(stderr,"dont have inputs\n");
d247a5d1 2148 continue;
61f8caf2 2149 }
41f170fd
MT
2150 CAmount nTxFees;
2151 CReserveTransactionDescriptor txDesc;
2152 bool isReserve = mempool.IsKnownReserveTransaction(hash, txDesc);
2153
a8419988 2154 nTxFees = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime) - tx.GetValueOut();
e9e70b95 2155
d247a5d1 2156 nTxSigOps += GetP2SHSigOpCount(tx, view);
a4a40a38 2157 if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
61f8caf2 2158 {
51376f3c 2159 //fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
d247a5d1 2160 continue;
61f8caf2 2161 }
41f170fd 2162
68f7d1d7
PT
2163 // Note that flags: we don't want to set mempool/IsStandard()
2164 // policy here, but we still have to ensure that the block we
2165 // create only contains transactions that are valid in new blocks.
d247a5d1 2166 CValidationState state;
6514771a 2167 PrecomputedTransactionData txdata(tx);
b76f691a 2168 if (!ContextualCheckInputs(tx, state, view, nHeight, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
61f8caf2 2169 {
51376f3c 2170 //fprintf(stderr,"context failure\n");
d247a5d1 2171 continue;
61f8caf2 2172 }
e7e14f44 2173
8cb98d91 2174 UpdateCoins(tx, view, nHeight);
d247a5d1 2175
41f170fd
MT
2176 if (isReserve)
2177 {
2178 reservePositions.push_back(nBlockTx);
2179 haveReserveTransactions = true;
efcc01c5 2180 additionalFees += txDesc.ReserveFees();
41f170fd
MT
2181 }
2182
31a04d28
SB
2183 BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
2184 sapling_tree.append(outDescription.cm);
2185 }
2186
d247a5d1
JG
2187 // Added
2188 pblock->vtx.push_back(tx);
2189 pblocktemplate->vTxFees.push_back(nTxFees);
2190 pblocktemplate->vTxSigOps.push_back(nTxSigOps);
2191 nBlockSize += nTxSize;
2192 ++nBlockTx;
2193 nBlockSigOps += nTxSigOps;
2194 nFees += nTxFees;
d247a5d1
JG
2195 if (fPrintPriority)
2196 {
3f0813b3 2197 LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString());
d247a5d1 2198 }
e9e70b95 2199
d247a5d1
JG
2200 // Add transactions that depend on this one to the priority queue
2201 if (mapDependers.count(hash))
2202 {
2203 BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
2204 {
2205 if (!porphan->setDependsOn.empty())
2206 {
2207 porphan->setDependsOn.erase(hash);
2208 if (porphan->setDependsOn.empty())
2209 {
c6cb21d1 2210 vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
d247a5d1
JG
2211 std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
2212 }
2213 }
2214 }
2215 }
2216 }
135fa24e 2217
05ece4c3 2218 // first calculate and distribute block rewards, including fees in the minerOutputs vector
88bc6df5 2219 CAmount rewardTotalShareAmount = 0;
855714b0 2220 CAmount rewardFees = nFees;
24d12992 2221 if (additionalFees.valueMap.count(thisChainID))
2222 {
2223 rewardFees += additionalFees.valueMap[thisChainID];
2224 additionalFees.valueMap.erase(thisChainID);
2225 }
2226
2227 CAmount verusFees = 0;
efcc01c5 2228 if (VERUS_CHAINID != ASSETCHAINS_CHAINID && additionalFees.valueMap.count(VERUS_CHAINID))
24d12992 2229 {
2230 verusFees += additionalFees.valueMap[VERUS_CHAINID];
2231 additionalFees.valueMap.erase(VERUS_CHAINID);
2232 }
2233
2234 if (additionalFees.valueMap.size())
2235 {
2236 printf("%s: burning reserve currency: %s\n", __func__, additionalFees.ToUniValue().write(1,2).c_str());
2237 }
2238
855714b0 2239 if (feePool.IsValid())
2240 {
c31944d3 2241 // we support only the current native currency or VRSC on PBaaS chains in the fee pool for now
24d12992 2242 feePool.reserveValues.valueMap[thisChainID] += rewardFees;
2243 if (verusFees)
2244 {
2245 feePool.reserveValues.valueMap[VERUS_CHAINID] += verusFees;
2246 }
2247 CFeePool oneFeeShare = feePool.OneFeeShare();
2248 rewardFees = oneFeeShare.reserveValues.valueMap[thisChainID];
855714b0 2249 feePool.reserveValues.valueMap[thisChainID] -= rewardFees;
2250
efcc01c5 2251 if (VERUS_CHAINID != ASSETCHAINS_CHAINID && oneFeeShare.reserveValues.valueMap.count(VERUS_CHAINID))
24d12992 2252 {
2253 verusFees = oneFeeShare.reserveValues.valueMap[VERUS_CHAINID];
2254 feePool.reserveValues.valueMap[VERUS_CHAINID] -= verusFees;
2255 }
2256
855714b0 2257 cp = CCinit(&CC, EVAL_FEE_POOL);
2258 pkCC = CPubKey(ParseHex(CC.CChexstr));
2259 coinbaseTx.vout.push_back(CTxOut(0,MakeMofNCCScript(CConditionObj<CFeePool>(EVAL_FEE_POOL,{pkCC.GetID()},1,&feePool))));
2260 }
efcc01c5 2261
2262 // printf("%s: rewardfees: %ld, verusfees: %ld\n", __func__, rewardFees, verusFees);
2263
c8c684e9 2264 CAmount rewardTotal = blockSubsidy + rewardFees;
41f170fd 2265
56fe75cb 2266 // now that we have the total reward, update the coinbase outputs
2267 if (isStake)
06f41160 2268 {
6e54f125 2269 // TODO: need to add reserve output to stake coinbase to prevent burning of VRSC
24d12992 2270 coinbaseTx.vout[0].nValue = rewardTotal;
88bc6df5 2271 }
56fe75cb 2272 else
88bc6df5 2273 {
56fe75cb 2274 for (auto &outputShare : minerOutputs)
06f41160 2275 {
855714b0 2276 rewardTotalShareAmount += outputShare.nValue;
88bc6df5 2277 }
41f170fd 2278
56fe75cb 2279 int cbOutIdx;
24d12992 2280 CAmount rewardLeft = rewardTotal;
2281 CAmount verusFeeLeft = verusFees;
56fe75cb 2282 for (cbOutIdx = 0; cbOutIdx < minerOutputs.size(); cbOutIdx++)
2283 {
855714b0 2284 CAmount amount = (arith_uint256(rewardTotal) * arith_uint256(minerOutputs[cbOutIdx].nValue) / arith_uint256(rewardTotalShareAmount)).GetLow64();
56fe75cb 2285 if (rewardLeft <= amount || (cbOutIdx + 1) == minerOutputs.size())
2286 {
2287 amount = rewardLeft;
2288 }
2289 rewardLeft -= amount;
24d12992 2290
2291 // now make outputs for non-native, VRSC fees
2292 if (verusFeeLeft)
2293 {
6e54f125 2294 CAmount verusFee = (arith_uint256(verusFees) * arith_uint256(minerOutputs[cbOutIdx].nValue) / arith_uint256(rewardTotalShareAmount)).GetLow64();
2295 if (verusFeeLeft <= verusFee || (cbOutIdx + 1) == minerOutputs.size())
24d12992 2296 {
6e54f125 2297 verusFee = verusFeeLeft;
24d12992 2298 }
2299 CTxDestination minerDestination;
2300 if (verusFee >= CFeePool::MIN_SHARE_SIZE && ExtractDestination(coinbaseTx.vout[cbOutIdx].scriptPubKey, minerDestination))
2301 {
2302 CTokenOutput to = CTokenOutput(VERUS_CHAINID, verusFee);
2303 coinbaseTx.vout[cbOutIdx].scriptPubKey = MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT,
2304 std::vector<CTxDestination>({minerDestination}),
2305 1,
2306 &to));
2307 }
2308 verusFeeLeft -= verusFee;
2309 }
2310
2311 // we had to wait to update this here to ensure it represented a correct distribution ratio
56fe75cb 2312 coinbaseTx.vout[cbOutIdx].nValue = amount;
56fe75cb 2313 }
88bc6df5
MT
2314 }
2315
88bc6df5
MT
2316 nLastBlockTx = nBlockTx;
2317 nLastBlockSize = nBlockSize;
2318
2319 blocktime = std::max(pindexPrev->GetMedianTimePast(), GetAdjustedTime());
2320
2321 pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
2322
41f170fd 2323 coinbaseTx.nExpiryHeight = 0;
88bc6df5 2324 coinbaseTx.nLockTime = blocktime;
abb90a89 2325
ebee7b5b 2326 // finalize input of coinbase
41f170fd
MT
2327 coinbaseTx.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(0)) + COINBASE_FLAGS;
2328 assert(coinbaseTx.vin[0].scriptSig.size() <= 100);
ebee7b5b 2329
88bc6df5
MT
2330 // coinbase is done
2331 pblock->vtx[0] = coinbaseTx;
2332 uint256 cbHash = coinbaseTx.GetHash();
ebee7b5b 2333
a9c8cca3 2334 // display it at block 1 for PBaaS debugging
2d9b4d0e 2335 /* if (nHeight == 1)
a9c8cca3 2336 {
2337 UniValue jsonTxOut(UniValue::VOBJ);
2338 TxToUniv(coinbaseTx, uint256(), jsonTxOut);
2339 printf("%s: new coinbase transaction: %s\n", __func__, jsonTxOut.write(1,2).c_str());
2d9b4d0e 2340 } */
a9c8cca3 2341
88bc6df5
MT
2342 // if there is a stake transaction, add it to the very end
2343 if (isStake)
2344 {
2345 UpdateCoins(txStaked, view, nHeight);
2346 pblock->vtx.push_back(txStaked);
2347 pblocktemplate->vTxFees.push_back(0);
2348 int txSigOps = GetLegacySigOpCount(txStaked);
2349 pblocktemplate->vTxSigOps.push_back(txSigOps);
2350 // already added to the block size above
2351 ++nBlockTx;
2352 nBlockSigOps += txSigOps;
2353 }
68b309c0 2354
88bc6df5 2355 extern CWallet *pwalletMain;
8577896f 2356
41f170fd 2357 pblock->vtx[0] = coinbaseTx;
d247a5d1 2358 pblocktemplate->vTxFees[0] = -nFees;
88bc6df5 2359 pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
48d800c2 2360
1fae37f6
MT
2361 // if not Verus stake, setup nonce, otherwise, leave it alone
2362 if (!isStake || ASSETCHAINS_LWMAPOS == 0)
2363 {
eb0a6550 2364 // Randomize nonce
1fae37f6 2365 arith_uint256 nonce = UintToArith256(GetRandHash());
48d800c2 2366
1fae37f6
MT
2367 // Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters)
2368 nonce <<= ASSETCHAINS_NONCESHIFT[ASSETCHAINS_ALGO];
2369 nonce >>= 16;
2370 pblock->nNonce = ArithToUint256(nonce);
2371 }
e9e70b95 2372
d247a5d1
JG
2373 // Fill in header
2374 pblock->hashPrevBlock = pindexPrev->GetBlockHash();
31a04d28 2375 pblock->hashFinalSaplingRoot = sapling_tree.root();
0c8fa56a
MT
2376
2377 // all Verus PoS chains need this data in the block at all times
2378 if ( ASSETCHAINS_LWMAPOS || ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || KOMODO_MININGTHREADS > 0 )
9a0f2798 2379 {
2380 UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
1fae37f6 2381 pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
9a0f2798 2382 }
12217420 2383
4d068367 2384 if ( ASSETCHAINS_SYMBOL[0] == 0 && IS_KOMODO_NOTARY != 0 && My_notaryid >= 0 )
af805d53 2385 {
28a62b60 2386 uint32_t r;
496f1fd2 2387 CMutableTransaction txNotary = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1);
fa04bcf3 2388 if ( pblock->nTime < pindexPrev->nTime+60 )
2389 pblock->nTime = pindexPrev->nTime + 60;
855714b0 2390
a893e994 2391 if ( komodo_notaryvin(txNotary,NOTARY_PUBKEY33) > 0 )
496f1fd2 2392 {
2d79309f 2393 CAmount txfees = 5000;
496f1fd2 2394 pblock->vtx.push_back(txNotary);
2395 pblocktemplate->vTxFees.push_back(txfees);
2396 pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txNotary));
2397 nFees += txfees;
2d79309f 2398 pblocktemplate->vTxFees[0] = -nFees;
c881e52b 2399 //*(uint64_t *)(&pblock->vtx[0].vout[0].nValue) += txfees;
f31815fc 2400 //fprintf(stderr,"added notaryvin\n");
0857c3d5 2401 }
2402 else
2403 {
2404 fprintf(stderr,"error adding notaryvin, need to create 0.0001 utxos\n");
2405 return(0);
2406 }
707b061c 2407 }
809f2e25 2408 else if ( ASSETCHAINS_CC == 0 && pindexPrev != 0 && ASSETCHAINS_STAKED == 0 && (ASSETCHAINS_SYMBOL[0] != 0 || IS_KOMODO_NOTARY == 0 || My_notaryid < 0) )
af805d53 2409 {
8fc79ac9 2410 CValidationState state;
809f2e25 2411 //fprintf(stderr,"check validity\n");
e6c5e0b8 2412 if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) // invokes CC checks
8fc79ac9 2413 {
9feb4b9e 2414 throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
8fc79ac9 2415 }
809f2e25 2416 //fprintf(stderr,"valid\n");
af805d53 2417 }
d247a5d1 2418 }
2a6a442a 2419 //fprintf(stderr,"done new block\n");
1685bba0
MT
2420
2421 // setup the header and buid the Merkle tree
2422 unsigned int extraNonce;
88d014d0 2423 IncrementExtraNonce(pblock, pindexPrev, extraNonce, true);
1685bba0 2424
d247a5d1
JG
2425 return pblocktemplate.release();
2426}
1db7bdb7 2427
855714b0 2428CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& _scriptPubKeyIn, bool isStake)
2429{
2430 std::vector<CTxOut> minerOutputs = _scriptPubKeyIn.size() ? std::vector<CTxOut>({CTxOut(1, _scriptPubKeyIn)}) : std::vector<CTxOut>();
2431 return CreateNewBlock(chainparams, minerOutputs, isStake);
2432}
acfa0333 2433
c1de826f
JG
2434//////////////////////////////////////////////////////////////////////////////
2435//
2436// Internal miner
2437//
2438
2cc0a252 2439#ifdef ENABLE_MINING
c1de826f 2440
88d014d0 2441class MinerAddressScript : public CReserveScript
2442{
2443 // CReserveScript requires implementing this function, so that if an
2444 // internal (not-visible) wallet address is used, the wallet can mark it as
2445 // important when a block is mined (so it then appears to the user).
2446 // If -mineraddress is set, the user already knows about and is managing the
2447 // address, so we don't need to do anything here.
2448 void KeepScript() {}
2449};
2450
2451void GetScriptForMinerAddress(boost::shared_ptr<CReserveScript> &script)
2452{
2453 CTxDestination addr = DecodeDestination(GetArg("-mineraddress", ""));
2454 if (!IsValidDestination(addr)) {
2455 return;
2456 }
2457
2458 boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
88d014d0 2459 script = mAddr;
fa6c618c 2460 script->reserveScript = GetScriptForDestination(addr);
88d014d0 2461}
2462
4a85e067 2463#ifdef ENABLE_WALLET
acfa0333
WL
2464//////////////////////////////////////////////////////////////////////////////
2465//
2466// Internal miner
2467//
acfa0333 2468
855714b0 2469CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, bool isStake)
acfa0333 2470{
fa6c618c 2471 CPubKey pubkey;
2472 CScript scriptPubKey;
2473 uint8_t *ptr;
2474 int32_t i;
2475 boost::shared_ptr<CReserveScript> coinbaseScript;
2476
d9f176ac 2477 if ( nHeight == 1 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
2478 {
2479 scriptPubKey = CScript() << ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY) << OP_CHECKSIG;
2480 }
2481 else if ( USE_EXTERNAL_PUBKEY != 0 )
998397aa 2482 {
7bfc207a 2483 //fprintf(stderr,"use notary pubkey\n");
c95fd5e0 2484 scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
f6c647ed 2485 }
fa6c618c 2486 else if (GetArg("-mineraddress", "").empty() || !(GetScriptForMinerAddress(coinbaseScript), (scriptPubKey = coinbaseScript->reserveScript).size()))
f6c647ed 2487 {
f1f6dfbb 2488 if (!isStake)
1b5b89ba 2489 {
f1f6dfbb 2490 if (!reservekey.GetReservedKey(pubkey))
2491 {
2492 return NULL;
2493 }
855714b0 2494 scriptPubKey = GetScriptForDestination(pubkey);
1b5b89ba 2495 }
f6c647ed 2496 }
855714b0 2497 return CreateNewBlock(Params(), scriptPubKey, isStake);
acfa0333
WL
2498}
2499
88d014d0 2500void komodo_broadcast(const CBlock *pblock,int32_t limit)
395f10cf 2501{
2502 int32_t n = 1;
2503 //fprintf(stderr,"broadcast new block t.%u\n",(uint32_t)time(NULL));
2504 {
2505 LOCK(cs_vNodes);
2506 BOOST_FOREACH(CNode* pnode, vNodes)
2507 {
2508 if ( pnode->hSocket == INVALID_SOCKET )
2509 continue;
2510 if ( (rand() % n) == 0 )
2511 {
2512 pnode->PushMessage("block", *pblock);
2513 if ( n++ > limit )
2514 break;
2515 }
2516 }
2517 }
2518 //fprintf(stderr,"finished broadcast new block t.%u\n",(uint32_t)time(NULL));
2519}
945f015d 2520
269d8ba0 2521static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
8e8b6d70
JG
2522#else
2523static bool ProcessBlockFound(CBlock* pblock)
2524#endif // ENABLE_WALLET
d247a5d1 2525{
572c763f 2526 int32_t height = chainActive.LastTip()->GetHeight()+1;
0ab273d2 2527 //LogPrintf("%s\n", pblock->ToString());
572c763f 2528 LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue), height);
af521e42 2529
d247a5d1
JG
2530 // Found a solution
2531 {
86131275 2532 if (pblock->hashPrevBlock != chainActive.LastTip()->GetBlockHash())
ba8419c7 2533 {
2534 uint256 hash; int32_t i;
2535 hash = pblock->hashPrevBlock;
92266e99 2536 for (i=31; i>=0; i--)
ba8419c7 2537 fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
c0dbb034 2538 fprintf(stderr," <- prev (stale)\n");
86131275 2539 hash = chainActive.LastTip()->GetBlockHash();
92266e99 2540 for (i=31; i>=0; i--)
ba8419c7 2541 fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
c0dbb034 2542 fprintf(stderr," <- chainTip (stale)\n");
e9e70b95 2543
ffde1589 2544 return error("VerusMiner: generated block is stale");
ba8419c7 2545 }
18e72167 2546 }
e9e70b95 2547
8e8b6d70 2548#ifdef ENABLE_WALLET
18e72167 2549 // Remove key from key pool
998397aa 2550 if ( IS_KOMODO_NOTARY == 0 )
945f015d 2551 {
2552 if (GetArg("-mineraddress", "").empty()) {
2553 // Remove key from key pool
2554 reservekey.KeepKey();
2555 }
8e8b6d70 2556 }
18e72167 2557 // Track how many getdata requests this block gets
438ba9c1 2558 //if ( 0 )
18e72167 2559 {
d1bc3a75 2560 //fprintf(stderr,"lock cs_wallet\n");
18e72167
PW
2561 LOCK(wallet.cs_wallet);
2562 wallet.mapRequestCount[pblock->GetHash()] = 0;
d247a5d1 2563 }
8e8b6d70 2564#endif
d1bc3a75 2565 //fprintf(stderr,"process new block\n");
194ad5b8 2566
c871d47f 2567 // Process this block (almost) the same as if we had received it from another node
18e72167 2568 CValidationState state;
88d014d0 2569 if (!ProcessNewBlock(1, chainActive.LastTip()->GetHeight()+1, state, Params(), NULL, pblock, true, NULL))
ffde1589 2570 return error("VerusMiner: ProcessNewBlock, block not accepted");
e9e70b95 2571
d793f94b 2572 TrackMinedBlock(pblock->GetHash());
395f10cf 2573 komodo_broadcast(pblock,16);
d247a5d1
JG
2574 return true;
2575}
2576
078f6af1 2577int32_t komodo_baseid(char *origbase);
a30dd993 2578int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t *blocktimes,int32_t *nonzpkeysp,int32_t height);
13691369 2579arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
8ee93080 2580int32_t FOUND_BLOCK,KOMODO_MAYBEMINED;
99ba67a0 2581extern int32_t KOMODO_LASTMINED,KOMODO_INSYNC;
8b51b9e4 2582int32_t roundrobin_delay;
18443f69 2583arith_uint256 HASHTarget,HASHTarget_POW;
3363d1c0 2584int32_t komodo_longestchain();
078f6af1 2585
5642c96c 2586// wait for peers to connect
12217420 2587void waitForPeers(const CChainParams &chainparams)
5642c96c 2588{
2589 if (chainparams.MiningRequiresPeers())
2590 {
3da69a31
MT
2591 bool fvNodesEmpty;
2592 {
00a7120e 2593 boost::this_thread::interruption_point();
3da69a31
MT
2594 LOCK(cs_vNodes);
2595 fvNodesEmpty = vNodes.empty();
2596 }
3363d1c0 2597 int longestchain = komodo_longestchain();
2598 int lastlongest = 0;
2599 if (fvNodesEmpty || IsNotInSync() || (longestchain != 0 && longestchain > chainActive.LastTip()->GetHeight()))
3da69a31 2600 {
af2e212d 2601 int loops = 0, blockDiff = 0, newDiff = 0;
2602
3da69a31 2603 do {
64d6048f 2604 if (fvNodesEmpty)
3da69a31 2605 {
69fa3d0e 2606 MilliSleep(1000 + rand() % 4000);
00a7120e 2607 boost::this_thread::interruption_point();
3da69a31
MT
2608 LOCK(cs_vNodes);
2609 fvNodesEmpty = vNodes.empty();
af2e212d 2610 loops = 0;
2611 blockDiff = 0;
3363d1c0 2612 lastlongest = 0;
af2e212d 2613 }
3363d1c0 2614 else if ((newDiff = IsNotInSync()) > 0)
af2e212d 2615 {
2616 if (blockDiff != newDiff)
2617 {
2618 blockDiff = newDiff;
2619 }
2620 else
2621 {
3363d1c0 2622 if (++loops <= 5)
af2e212d 2623 {
2624 MilliSleep(1000);
2625 }
2626 else break;
2627 }
3363d1c0 2628 lastlongest = 0;
2629 }
2630 else if (!fvNodesEmpty && !IsNotInSync() && longestchain > chainActive.LastTip()->GetHeight())
2631 {
2632 // the only thing may be that we are seeing a long chain that we'll never get
2633 // don't wait forever
2634 if (lastlongest == 0)
2635 {
2636 MilliSleep(3000);
2637 lastlongest = longestchain;
2638 }
3da69a31 2639 }
af2e212d 2640 } while (fvNodesEmpty || IsNotInSync());
2603640e 2641 MilliSleep(500 + rand() % 1000);
3da69a31 2642 }
5642c96c 2643 }
2644}
2645
42181656 2646#ifdef ENABLE_WALLET
d7e6718d
MT
2647CBlockIndex *get_chainactive(int32_t height)
2648{
3c40a9a6 2649 if ( chainActive.LastTip() != 0 )
d7e6718d 2650 {
4b729ec5 2651 if ( height <= chainActive.LastTip()->GetHeight() )
3c40a9a6
MT
2652 {
2653 LOCK(cs_main);
d7e6718d 2654 return(chainActive[height]);
3c40a9a6 2655 }
4b729ec5 2656 // else fprintf(stderr,"get_chainactive height %d > active.%d\n",height,chainActive.Tip()->GetHeight());
d7e6718d
MT
2657 }
2658 //fprintf(stderr,"get_chainactive null chainActive.Tip() height %d\n",height);
2659 return(0);
2660}
2661
135fa24e 2662/*
2663 * A separate thread to stake, while the miner threads mine.
2664 */
2665void static VerusStaker(CWallet *pwallet)
2666{
2667 LogPrintf("Verus staker thread started\n");
2668 RenameThread("verus-staker");
2669
2670 const CChainParams& chainparams = Params();
2d02c19e 2671 auto consensusParams = chainparams.GetConsensus();
76f69285 2672 bool isNotaryConnected = ConnectedChains.CheckVerusPBaaSAvailable();
135fa24e 2673
2674 // Each thread has its own key
2675 CReserveKey reservekey(pwallet);
2676
2677 // Each thread has its own counter
2678 unsigned int nExtraNonce = 0;
12217420 2679
135fa24e 2680 uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
2681
4b729ec5 2682 while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->GetHeight() != 235300 &&
135fa24e 2683 {
2684 sleep(1);
2685 if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
2686 break;
2687 }
2688
2689 // try a nice clean peer connection to start
bf9c36f4
MT
2690 CBlockIndex *pindexPrev, *pindexCur;
2691 do {
2692 pindexPrev = chainActive.LastTip();
2693 MilliSleep(5000 + rand() % 5000);
2694 waitForPeers(chainparams);
2695 pindexCur = chainActive.LastTip();
2696 } while (pindexPrev != pindexCur);
c132b91a 2697
135fa24e 2698 try {
0fc0dc56 2699 static int32_t lastStakingHeight = 0;
2700
135fa24e 2701 while (true)
2702 {
135fa24e 2703 waitForPeers(chainparams);
4ca6678c 2704 CBlockIndex* pindexPrev = chainActive.LastTip();
135fa24e 2705
2706 // Create new block
2707 unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
0fc0dc56 2708
4b729ec5 2709 if ( Mining_height != pindexPrev->GetHeight()+1 )
135fa24e 2710 {
4b729ec5 2711 Mining_height = pindexPrev->GetHeight()+1;
135fa24e 2712 Mining_start = (uint32_t)time(NULL);
2713 }
2714
1fae37f6
MT
2715 // Check for stop or if block needs to be rebuilt
2716 boost::this_thread::interruption_point();
2717
135fa24e 2718 // try to stake a block
1fae37f6 2719 CBlockTemplate *ptr = NULL;
31609f35 2720
2721 // get height locally for consistent reporting
2722 int32_t newHeight = Mining_height;
2723
2724 if (newHeight > VERUS_MIN_STAKEAGE)
855714b0 2725 ptr = CreateNewBlockWithKey(reservekey, newHeight, true);
135fa24e 2726
a73ab4b4 2727 // TODO - putting this output here tends to help mitigate announcing a staking height earlier than
2728 // announcing the last block win when we start staking before a block's acceptance has been
2729 // acknowledged by the mining thread - a better solution may be to put the output on the submission
2730 // thread.
31609f35 2731 if ( ptr == 0 && newHeight != lastStakingHeight )
a73ab4b4 2732 {
31609f35 2733 printf("Staking height %d for %s\n", newHeight, ASSETCHAINS_SYMBOL);
a73ab4b4 2734 }
31609f35 2735 lastStakingHeight = newHeight;
a73ab4b4 2736
135fa24e 2737 if ( ptr == 0 )
2738 {
67dceeec 2739 if (newHeight == 1 && (isNotaryConnected = ConnectedChains.IsNotaryAvailable()))
76f69285 2740 {
2741 static int outputCounter;
2742 if (outputCounter++ % 60 == 0)
2743 {
695db088 2744 printf("%s: waiting for confirmation of launch at or after block %u on %s before mining block 1\n", __func__,
2745 (uint32_t)ConnectedChains.ThisChain().startBlock,
76f69285 2746 ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
2747 sleep(1);
2748 }
2749 }
1fae37f6 2750 // wait to try another staking block until after the tip moves again
37ad6886 2751 while ( chainActive.LastTip() == pindexPrev )
bab13dd2 2752 MilliSleep(250);
76f69285 2753 if (newHeight == 1)
2754 {
2755 sleep(10);
2756 }
135fa24e 2757 continue;
2758 }
2759
2760 unique_ptr<CBlockTemplate> pblocktemplate(ptr);
2761 if (!pblocktemplate.get())
2762 {
2763 if (GetArg("-mineraddress", "").empty()) {
1fae37f6 2764 LogPrintf("Error in %s staker: Keypool ran out, please call keypoolrefill before restarting the mining thread\n",
135fa24e 2765 ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2766 } else {
2767 // Should never reach here, because -mineraddress validity is checked in init.cpp
1fae37f6 2768 LogPrintf("Error in %s staker: Invalid %s -mineraddress\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], ASSETCHAINS_SYMBOL);
135fa24e 2769 }
2770 return;
2771 }
2772
2773 CBlock *pblock = &pblocktemplate->block;
1fae37f6 2774 LogPrintf("Staking with %u transactions in block (%u bytes)\n", pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
135fa24e 2775 //
2776 // Search
2777 //
1fae37f6
MT
2778 int64_t nStart = GetTime();
2779
1fae37f6
MT
2780 if (vNodes.empty() && chainparams.MiningRequiresPeers())
2781 {
2782 if ( Mining_height > ASSETCHAINS_MINHEIGHT )
2783 {
2784 fprintf(stderr,"no nodes, attempting reconnect\n");
2785 continue;
2786 }
2787 }
2788
2789 if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
2790 {
2791 fprintf(stderr,"timeout, retrying\n");
2792 continue;
2793 }
135fa24e 2794
37ad6886 2795 if ( pindexPrev != chainActive.LastTip() )
135fa24e 2796 {
4b729ec5 2797 printf("Block %d added to chain\n", chainActive.LastTip()->GetHeight());
135fa24e 2798 MilliSleep(250);
2799 continue;
2800 }
2801
1fae37f6
MT
2802 int32_t unlockTime = komodo_block_unlocktime(Mining_height);
2803 int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
135fa24e 2804
1fae37f6 2805 uint256 hashTarget = ArithToUint256(arith_uint256().SetCompact(pblock->nBits));
135fa24e 2806
df756d24 2807 pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
b9956efc 2808
df756d24 2809 UpdateTime(pblock, consensusParams, pindexPrev);
b9956efc 2810
ed47e5ec
MT
2811 if (ProcessBlockFound(pblock, *pwallet, reservekey))
2812 {
2813 LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2814 LogPrintf("Staked block found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
31609f35 2815 printf("Found block %d \n", newHeight);
ed47e5ec
MT
2816 printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
2817 arith_uint256 post;
2818 post.SetCompact(pblock->GetVerusPOSTarget());
31609f35 2819
ed47e5ec
MT
2820 CTransaction &sTx = pblock->vtx[pblock->vtx.size()-1];
2821 printf("POS hash: %s \ntarget: %s\n",
31609f35 2822 CTransaction::_GetVerusPOSHash(&(pblock->nNonce),
2823 sTx.vin[0].prevout.hash,
2824 sTx.vin[0].prevout.n,
2825 newHeight,
8d2b052e 2826 chainActive.GetVerusEntropyHash(newHeight),
31609f35 2827 sTx.vout[0].nValue).GetHex().c_str(),
2828 ArithToUint256(post).GetHex().c_str());
2829 if (unlockTime > newHeight && subsidy >= ASSETCHAINS_TIMELOCKGTE)
ed47e5ec
MT
2830 printf("- timelocked until block %i\n", unlockTime);
2831 else
2832 printf("\n");
2833 }
1fae37f6 2834 else
ed47e5ec
MT
2835 {
2836 LogPrintf("Found block rejected at staking height: %d\n", Mining_height);
2837 printf("Found block rejected at staking height: %d\n", Mining_height);
2838 }
135fa24e 2839
1fae37f6
MT
2840 // Check for stop or if block needs to be rebuilt
2841 boost::this_thread::interruption_point();
135fa24e 2842
bf9c36f4 2843 sleep(3);
3da69a31 2844
1fae37f6
MT
2845 // In regression test mode, stop mining after a block is found.
2846 if (chainparams.MineBlocksOnDemand()) {
2847 throw boost::thread_interrupted();
135fa24e 2848 }
2849 }
2850 }
2851 catch (const boost::thread_interrupted&)
2852 {
135fa24e 2853 LogPrintf("VerusStaker terminated\n");
2854 throw;
2855 }
2856 catch (const std::runtime_error &e)
2857 {
135fa24e 2858 LogPrintf("VerusStaker runtime error: %s\n", e.what());
2859 return;
2860 }
135fa24e 2861}
2862
c17dbdee 2863typedef bool (*minefunction)(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
2864bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
2865bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
fa7fdbc6 2866
42181656 2867void static BitcoinMiner_noeq(CWallet *pwallet)
2868#else
2869void static BitcoinMiner_noeq()
2870#endif
2871{
05f6e633 2872 LogPrintf("%s miner started\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
05f6e633 2873 RenameThread("verushash-miner");
42181656 2874
2875#ifdef ENABLE_WALLET
2876 // Each thread has its own key
2877 CReserveKey reservekey(pwallet);
2878#endif
2879
248084b7 2880 miningTimer.clear();
2881
2910478b 2882 const CChainParams& chainparams = Params();
42181656 2883 // Each thread has its own counter
2884 unsigned int nExtraNonce = 0;
12217420 2885
42181656 2886 uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
2887
4b729ec5 2888 while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->GetHeight() != 235300 &&
42181656 2889 {
2890 sleep(1);
2891 if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
2892 break;
2893 }
9f3e2213 2894
3da69a31
MT
2895 SetThreadPriority(THREAD_PRIORITY_LOWEST);
2896
5642c96c 2897 // try a nice clean peer connection to start
c132b91a 2898 CBlockIndex *pindexPrev, *pindexCur;
9f3e2213 2899 do {
37ad6886 2900 pindexPrev = chainActive.LastTip();
3da69a31 2901 MilliSleep(5000 + rand() % 5000);
bf9c36f4 2902 waitForPeers(chainparams);
37ad6886 2903 pindexCur = chainActive.LastTip();
c132b91a 2904 } while (pindexPrev != pindexCur);
6176a421 2905
a9f18272 2906 // make sure that we have checked for PBaaS availability
2907 ConnectedChains.CheckVerusPBaaSAvailable();
2908
dbe656fe
MT
2909 // this will not stop printing more than once in all cases, but it will allow us to print in all cases
2910 // and print duplicates rarely without having to synchronize
2911 static CBlockIndex *lastChainTipPrinted;
90198f71 2912 static int32_t lastMiningHeight = 0;
9f3e2213 2913
42181656 2914 miningTimer.start();
2915
2916 try {
dbe656fe 2917 printf("Mining %s with %s\n", ASSETCHAINS_SYMBOL, ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
08d46b7f 2918
42181656 2919 while (true)
2920 {
68334c8d 2921 miningTimer.stop();
2922 waitForPeers(chainparams);
dfcf8255 2923
37ad6886 2924 pindexPrev = chainActive.LastTip();
dfcf8255 2925
f8f61a6d 2926 // prevent forking on startup before the diff algorithm kicks in,
2927 // but only for a startup Verus test chain. PBaaS chains have the difficulty inherited from
2928 // their parent
57055854 2929 if (chainparams.MiningRequiresPeers() && ((IsVerusActive() && pindexPrev->GetHeight() < 50) || pindexPrev != chainActive.LastTip()))
dfcf8255
MT
2930 {
2931 do {
37ad6886 2932 pindexPrev = chainActive.LastTip();
2830db29 2933 MilliSleep(2000 + rand() % 2000);
37ad6886 2934 } while (pindexPrev != chainActive.LastTip());
dfcf8255 2935 }
42181656 2936
2937 // Create new block
2938 unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
4b729ec5 2939 if ( Mining_height != pindexPrev->GetHeight()+1 )
42181656 2940 {
4b729ec5 2941 Mining_height = pindexPrev->GetHeight()+1;
90198f71 2942 if (lastMiningHeight != Mining_height)
2943 {
2944 lastMiningHeight = Mining_height;
dc74c06d 2945 printf("Mining %s at height %d\n", ASSETCHAINS_SYMBOL, Mining_height);
90198f71 2946 }
42181656 2947 Mining_start = (uint32_t)time(NULL);
2948 }
2949
dbe656fe 2950 miningTimer.start();
42181656 2951
2952#ifdef ENABLE_WALLET
855714b0 2953 CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height);
42181656 2954#else
2955 CBlockTemplate *ptr = CreateNewBlockWithKey();
2956#endif
2957 if ( ptr == 0 )
2958 {
2959 static uint32_t counter;
f6084562
MT
2960 if ( counter++ % 40 == 0 )
2961 {
2962 if (!IsVerusActive() &&
67dceeec 2963 ConnectedChains.IsNotaryAvailable() &&
76f69285 2964 !ConnectedChains.readyToStart)
f6084562 2965 {
695db088 2966 fprintf(stderr,"waiting for confirmation of launch at or after block %u on %s chain to start\n", (uint32_t)ConnectedChains.ThisChain().startBlock,
c8c684e9 2967 ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
f6084562
MT
2968 }
2969 else
2970 {
2971 fprintf(stderr,"Unable to create valid block... will continue to try\n");
2972 }
2973 }
2830db29 2974 MilliSleep(2000);
42181656 2975 continue;
2976 }
dbe656fe 2977
42181656 2978 unique_ptr<CBlockTemplate> pblocktemplate(ptr);
2979 if (!pblocktemplate.get())
2980 {
2981 if (GetArg("-mineraddress", "").empty()) {
05f6e633 2982 LogPrintf("Error in %s miner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n",
2983 ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
42181656 2984 } else {
2985 // Should never reach here, because -mineraddress validity is checked in init.cpp
05f6e633 2986 LogPrintf("Error in %s miner: Invalid %s -mineraddress\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], ASSETCHAINS_SYMBOL);
42181656 2987 }
02dbe9a3 2988 miningTimer.stop();
248084b7 2989 miningTimer.clear();
42181656 2990 return;
2991 }
2992 CBlock *pblock = &pblocktemplate->block;
f8f61a6d 2993
2994 uint32_t savebits;
2995 bool mergeMining = false;
2996 savebits = pblock->nBits;
2997
1e435b54 2998 uint32_t solutionVersion = CConstVerusSolutionVector::Version(pblock->nSolution);
f37d48ca 2999 if (pblock->nVersion != CBlockHeader::VERUS_V2)
3000 {
3001 // must not be in sync
3002 printf("Mining on incorrect block version.\n");
3003 sleep(2);
3004 continue;
3005 }
d3dfc922 3006 bool verusSolutionPBaaS = solutionVersion >= CActivationHeight::ACTIVATE_PBAAS;
f8f61a6d 3007
c17dbdee 3008 // v2 hash writer with adjustments for the current height
3009 CVerusHashV2bWriter ss2 = CVerusHashV2bWriter(SER_GETHASH, PROTOCOL_VERSION, solutionVersion);
3010
42181656 3011 if ( ASSETCHAINS_SYMBOL[0] != 0 )
3012 {
3013 if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
3014 {
3015 if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
3016 {
3017 static uint32_t counter;
3018 if ( counter++ < 10 )
3019 fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL);
3020 sleep(10);
3021 continue;
3022 } else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
3023 }
3024 }
b2a98c42 3025
c871d47f 3026 // set our easiest target, if V3+, no need to rebuild the merkle tree
f37d48ca 3027 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, verusSolutionPBaaS ? false : true, &savebits);
b2a98c42
MT
3028
3029 // update PBaaS header
f37d48ca 3030 if (verusSolutionPBaaS)
b2a98c42 3031 {
2fd1f0fb 3032 if (!IsVerusActive() && ConnectedChains.IsVerusPBaaSAvailable())
f8f61a6d 3033 {
b2a98c42 3034
2fd1f0fb 3035 UniValue params(UniValue::VARR);
3036 UniValue error(UniValue::VARR);
3037 params.push_back(EncodeHexBlk(*pblock));
3038 params.push_back(ASSETCHAINS_SYMBOL);
3039 params.push_back(ASSETCHAINS_RPCHOST);
3040 params.push_back(ASSETCHAINS_RPCPORT);
3041 params.push_back(ASSETCHAINS_RPCCREDENTIALS);
3042 try
b2a98c42 3043 {
be17c611 3044 ConnectedChains.lastSubmissionFailed = false;
2fd1f0fb 3045 params = RPCCallRoot("addmergedblock", params);
3046 params = find_value(params, "result");
3047 error = find_value(params, "error");
3048 } catch (std::exception e)
3049 {
c8c684e9 3050 printf("Failed to connect to %s chain\n", ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
2fd1f0fb 3051 params = UniValue(e.what());
b2a98c42 3052 }
2fd1f0fb 3053 if (mergeMining = (params.isNull() && error.isNull()))
f8f61a6d 3054 {
c8c684e9 3055 printf("Merge mining %s with %s as the hashing chain\n", ASSETCHAINS_SYMBOL, ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
3056 LogPrintf("Merge mining with %s as the hashing chain\n", ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
f8f61a6d 3057 }
b2a98c42
MT
3058 }
3059 }
3060
42181656 3061 LogPrintf("Running %s miner with %u transactions in block (%u bytes)\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO],
3062 pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
3063 //
3064 // Search
3065 //
f8f61a6d 3066 int64_t nStart = GetTime();
42181656 3067
f8f61a6d 3068 arith_uint256 hashTarget = arith_uint256().SetCompact(savebits);
fa7fdbc6 3069 uint256 uintTarget = ArithToUint256(hashTarget);
f8f61a6d 3070 arith_uint256 ourTarget;
3071 ourTarget.SetCompact(pblock->nBits);
3072
42181656 3073 Mining_start = 0;
ef70c5b2 3074
37ad6886 3075 if ( pindexPrev != chainActive.LastTip() )
05f6e633 3076 {
37ad6886 3077 if (lastChainTipPrinted != chainActive.LastTip())
dbe656fe 3078 {
37ad6886 3079 lastChainTipPrinted = chainActive.LastTip();
4b729ec5 3080 printf("Block %d added to chain\n", lastChainTipPrinted->GetHeight());
dbe656fe 3081 }
f8f61a6d 3082 MilliSleep(100);
05f6e633 3083 continue;
3084 }
ef70c5b2 3085
2830db29 3086 uint64_t count;
3087 uint64_t hashesToGo = 0;
3088 uint64_t totalDone = 0;
3089
e29b5dd5 3090 int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
fa7fdbc6 3091 count = ((ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1) / ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
db027133 3092 CVerusHashV2 *vh2 = &ss2.GetState();
3b500530 3093 u128 *hashKey;
3094 verusclhasher &vclh = vh2->vclh;
fa7fdbc6 3095 minefunction mine_verus;
3096 mine_verus = IsCPUVerusOptimized() ? &mine_verus_v2 : &mine_verus_v2_port;
f21fad6a 3097
42181656 3098 while (true)
3099 {
4dcb64c0 3100 uint256 hashResult = uint256();
458bfcab 3101
e5fb645e 3102 unsigned char *curBuf;
3103
f8f61a6d 3104 if (mergeMining)
42181656 3105 {
c89d86ee 3106 // loop for a few minutes before refreshing the block
e771a884 3107 while (true)
12217420 3108 {
93ff475b 3109 uint256 ourMerkle = pblock->hashMerkleRoot;
a1d91f89 3110 if ( pindexPrev != chainActive.LastTip() )
3111 {
3112 if (lastChainTipPrinted != chainActive.LastTip())
3113 {
3114 lastChainTipPrinted = chainActive.LastTip();
3115 printf("Block %d added to chain\n\n", lastChainTipPrinted->GetHeight());
3116 arith_uint256 target;
3117 target.SetCompact(lastChainTipPrinted->nBits);
93ff475b
MT
3118 if (ourMerkle == lastChainTipPrinted->hashMerkleRoot)
3119 {
3120 LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", lastChainTipPrinted->GetBlockHash().GetHex().c_str(), ArithToUint256(ourTarget).GetHex().c_str());
607402ba 3121 printf("Found block %d \n", lastChainTipPrinted->GetHeight());
93ff475b
MT
3122 printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
3123 printf(" hash: %s\ntarget: %s\n", lastChainTipPrinted->GetBlockHash().GetHex().c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3124 }
a1d91f89 3125 }
3126 break;
3127 }
3128
e771a884 3129 // if PBaaS is no longer available, we can't count on merge mining
3130 if (!ConnectedChains.IsVerusPBaaSAvailable())
3131 {
3132 break;
3133 }
f8f61a6d 3134
3135 if (vNodes.empty() && chainparams.MiningRequiresPeers())
458bfcab 3136 {
f8f61a6d 3137 if ( Mining_height > ASSETCHAINS_MINHEIGHT )
fa7fdbc6 3138 {
f8f61a6d 3139 fprintf(stderr,"no nodes, attempting reconnect\n");
3140 break;
fa7fdbc6 3141 }
f8f61a6d 3142 }
3143
a82942e4 3144 // update every few minutes, regardless
3145 int64_t elapsed = GetTime() - nStart;
f8f61a6d 3146
a9663647 3147 if ((mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && elapsed > 60) || elapsed > 60 || ConnectedChains.lastSubmissionFailed)
458bfcab 3148 {
f8f61a6d 3149 break;
458bfcab 3150 }
a1d91f89 3151
dc74c06d 3152 boost::this_thread::interruption_point();
a1d91f89 3153 MilliSleep(500);
458bfcab 3154 }
ffde1589 3155 break;
f8f61a6d 3156 }
3157 else
3158 {
3159 // check NONCEMASK at a time
3160 for (uint64_t i = 0; i < count; i++)
42181656 3161 {
2fd1f0fb 3162 // this is the actual mining loop, which enables us to drop out and queue a header anytime we earn a block that is good enough for a
f8f61a6d 3163 // merge mined block, but not our own
f8f61a6d 3164 bool blockFound;
3165 arith_uint256 arithHash;
2830db29 3166 totalDone = 0;
f8f61a6d 3167 do
3168 {
2fd1f0fb 3169 // pickup/remove any new/deleted headers
71f97948 3170 if (ConnectedChains.dirty || (pblock->NumPBaaSHeaders() < ConnectedChains.mergeMinedChains.size() + 1))
2fd1f0fb 3171 {
f37d48ca 3172 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, verusSolutionPBaaS ? false : true, &savebits);
1fa4454d 3173
2fd1f0fb 3174 hashTarget.SetCompact(savebits);
3175 uintTarget = ArithToUint256(hashTarget);
3176 }
3177
f8f61a6d 3178 // hashesToGo gets updated with actual number run for metrics
3179 hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
2830db29 3180 uint64_t start = i * hashesToGo + totalDone;
f8f61a6d 3181 hashesToGo -= totalDone;
3182
f37d48ca 3183 if (verusSolutionPBaaS)
f8f61a6d 3184 {
3185 // mine on canonical header for merge mining
3186 CPBaaSPreHeader savedHeader(*pblock);
da97aa5c 3187
f8f61a6d 3188 pblock->ClearNonCanonicalData();
c17dbdee 3189 blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
f8f61a6d 3190 savedHeader.SetBlockData(*pblock);
3191 }
3192 else
3193 {
c17dbdee 3194 blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
f8f61a6d 3195 }
3196
3197 arithHash = UintToArith256(hashResult);
249e20e4 3198 totalDone += hashesToGo + 1;
f8f61a6d 3199 if (blockFound && IsVerusActive())
3200 {
3201 ConnectedChains.QueueNewBlockHeader(*pblock);
3202 if (arithHash > ourTarget)
3203 {
3204 // all blocks qualified with this hash will be submitted
3205 // until we redo the block, we might as well not try again with anything over this hash
3206 hashTarget = arithHash;
3207 uintTarget = ArithToUint256(hashTarget);
3208 }
3209 }
2fd1f0fb 3210 } while (blockFound && arithHash > ourTarget);
c98efb5a 3211
f8f61a6d 3212 if (!blockFound || arithHash > ourTarget)
4dcb64c0 3213 {
f8f61a6d 3214 // Check for stop or if block needs to be rebuilt
3215 boost::this_thread::interruption_point();
ce40cf2e 3216 if ( pindexPrev != chainActive.LastTip() )
f8f61a6d 3217 {
3218 if (lastChainTipPrinted != chainActive.LastTip())
3219 {
3220 lastChainTipPrinted = chainActive.LastTip();
3221 printf("Block %d added to chain\n", lastChainTipPrinted->GetHeight());
3222 }
3223 break;
3224 }
a1d91f89 3225 else if ((i + 1) < count)
f8f61a6d 3226 {
a1d91f89 3227 // if we'll not drop through, update hashcount
f8f61a6d 3228 {
02dbe9a3 3229 miningTimer += totalDone;
2830db29 3230 totalDone = 0;
f8f61a6d 3231 }
f8f61a6d 3232 }
4dcb64c0 3233 }
f8f61a6d 3234 else
3235 {
3236 // Check for stop or if block needs to be rebuilt
3237 boost::this_thread::interruption_point();
4dcb64c0 3238
f8f61a6d 3239 if (pblock->nSolution.size() != 1344)
3240 {
3241 LogPrintf("ERROR: Block solution is not 1344 bytes as it should be");
3242 break;
3243 }
42181656 3244
f8f61a6d 3245 SetThreadPriority(THREAD_PRIORITY_NORMAL);
3246
3247 int32_t unlockTime = komodo_block_unlocktime(Mining_height);
ef70c5b2 3248
3363d1c0 3249#ifdef VERUSHASHDEBUG
f8f61a6d 3250 std::string validateStr = hashResult.GetHex();
3251 std::string hashStr = pblock->GetHash().GetHex();
3252 uint256 *bhalf1 = (uint256 *)vh2->CurBuffer();
3253 uint256 *bhalf2 = bhalf1 + 1;
3363d1c0 3254#else
f8f61a6d 3255 std::string hashStr = hashResult.GetHex();
3363d1c0 3256#endif
3af22e67 3257
f8f61a6d 3258 LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
3259 LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hashStr, ArithToUint256(ourTarget).GetHex());
3260 printf("Found block %d \n", Mining_height );
3261 printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
3363d1c0 3262#ifdef VERUSHASHDEBUG
f8f61a6d 3263 printf(" hash: %s\n val: %s \ntarget: %s\n\n", hashStr.c_str(), validateStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3264 printf("intermediate %lx\n", intermediate);
3265 printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
3266 bhalf1 = (uint256 *)verusclhasher_key.get();
3267 bhalf2 = bhalf1 + ((vh2->vclh.keyMask + 1) >> 5);
3268 printf(" Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
3363d1c0 3269#else
f8f61a6d 3270 printf(" hash: %s\ntarget: %s", hashStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3363d1c0 3271#endif
f8f61a6d 3272 if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
3273 printf(" - timelocked until block %i\n", unlockTime);
3274 else
3275 printf("\n");
42181656 3276#ifdef ENABLE_WALLET
f8f61a6d 3277 ProcessBlockFound(pblock, *pwallet, reservekey);
42181656 3278#else
f8f61a6d 3279 ProcessBlockFound(pblock);
42181656 3280#endif
f8f61a6d 3281 SetThreadPriority(THREAD_PRIORITY_LOWEST);
3282 break;
3283 }
42181656 3284 }
42181656 3285
f8f61a6d 3286 {
02dbe9a3 3287 miningTimer += totalDone;
f8f61a6d 3288 }
69767347 3289 }
f8f61a6d 3290
69767347 3291
42181656 3292 // Check for stop or if block needs to be rebuilt
3293 boost::this_thread::interruption_point();
3294
3295 if (vNodes.empty() && chainparams.MiningRequiresPeers())
3296 {
3297 if ( Mining_height > ASSETCHAINS_MINHEIGHT )
3298 {
ef70c5b2 3299 fprintf(stderr,"no nodes, attempting reconnect\n");
42181656 3300 break;
3301 }
3302 }
3303
dbe656fe 3304 if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
42181656 3305 {
dbe656fe 3306 fprintf(stderr,"timeout, retrying\n");
42181656 3307 break;
3308 }
3309
37ad6886 3310 if ( pindexPrev != chainActive.LastTip() )
42181656 3311 {
37ad6886 3312 if (lastChainTipPrinted != chainActive.LastTip())
dbe656fe 3313 {
37ad6886 3314 lastChainTipPrinted = chainActive.LastTip();
90198f71 3315 printf("Block %d added to chain\n\n", lastChainTipPrinted->GetHeight());
dbe656fe 3316 }
42181656 3317 break;
3318 }
3319
2830db29 3320 // totalDone now has the number of hashes actually done since starting on one nonce mask worth
ce40cf2e 3321 uint64_t hashesPerNonceMask = ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3;
2830db29 3322 if (!(totalDone < hashesPerNonceMask))
ce40cf2e 3323 {
52cf66e1 3324#ifdef _WIN32
ce40cf2e 3325 printf("%llu mega hashes complete - working\n", (hashesPerNonceMask + 1) / 1048576);
52cf66e1 3326#else
ce40cf2e 3327 printf("%lu mega hashes complete - working\n", (hashesPerNonceMask + 1) / 1048576);
52cf66e1 3328#endif
ce40cf2e 3329 }
4dcb64c0 3330 break;
8682e17a 3331
42181656 3332 }
3333 }
3334 }
3335 catch (const boost::thread_interrupted&)
3336 {
3337 miningTimer.stop();
248084b7 3338 miningTimer.clear();
5034d1c1 3339 LogPrintf("%s miner terminated\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
42181656 3340 throw;
3341 }
3342 catch (const std::runtime_error &e)
3343 {
3344 miningTimer.stop();
248084b7 3345 miningTimer.clear();
5034d1c1 3346 LogPrintf("%s miner runtime error: %s\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], e.what());
42181656 3347 return;
3348 }
3349 miningTimer.stop();
248084b7 3350 miningTimer.clear();
42181656 3351}
3352
8e8b6d70 3353#ifdef ENABLE_WALLET
e9e70b95 3354 void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
8e8b6d70 3355#else
e9e70b95 3356 void GenerateBitcoins(bool fGenerate, int nThreads)
8e8b6d70 3357#endif
d247a5d1 3358 {
9ae83faa 3359 static CCriticalSection cs_startmining;
3360
3361 LOCK(cs_startmining);
f8f61a6d 3362 if (!AreParamsInitialized())
3363 {
3364 return;
3365 }
3366
b20c38cc 3367 VERUS_MINTBLOCKS = (VERUS_MINTBLOCKS && ASSETCHAINS_LWMAPOS != 0);
bd6639fd 3368
89cd7b59 3369 if (fGenerate == true || VERUS_MINTBLOCKS)
10214558 3370 {
89cd7b59
MT
3371 mapArgs["-gen"] = "1";
3372
6e62f837 3373 if (VERUS_DEFAULT_ZADDR.size() > 0)
99c94fc3 3374 {
6e62f837 3375 if (defaultSaplingDest == boost::none)
89cd7b59 3376 {
6e62f837 3377 LogPrintf("ERROR: -defaultzaddr parameter is invalid Sapling payment address\n");
3378 fprintf(stderr, "-defaultzaddr parameter is invalid Sapling payment address\n");
89cd7b59
MT
3379 }
3380 else
3381 {
6e62f837 3382 LogPrintf("StakeGuard searching for double stakes on %s\n", VERUS_DEFAULT_ZADDR.c_str());
3383 fprintf(stderr, "StakeGuard searching for double stakes on %s\n", VERUS_DEFAULT_ZADDR.c_str());
89cd7b59 3384 }
99c94fc3 3385 }
3386 }
10214558 3387
e9e70b95 3388 static boost::thread_group* minerThreads = NULL;
28424e9f 3389
e9e70b95 3390 if (nThreads < 0)
3391 nThreads = GetNumCores();
9ae83faa 3392
e9e70b95 3393 if (minerThreads != NULL)
3394 {
3395 minerThreads->interrupt_all();
88d014d0 3396 minerThreads->join_all();
e9e70b95 3397 delete minerThreads;
3398 minerThreads = NULL;
3399 }
135fa24e 3400
afaeb54b 3401 //fprintf(stderr,"nThreads.%d fGenerate.%d\n",(int32_t)nThreads,fGenerate);
5034d1c1 3402 if ( nThreads == 0 && ASSETCHAINS_STAKED )
3a446d9f 3403 nThreads = 1;
5034d1c1 3404
28424e9f 3405 if (!fGenerate)
e9e70b95 3406 return;
135fa24e 3407
e9e70b95 3408 minerThreads = new boost::thread_group();
135fa24e 3409
85c51d62 3410 // add the PBaaS thread when mining or staking
3411 minerThreads->create_thread(boost::bind(&CConnectedChains::SubmissionThreadStub));
3412
135fa24e 3413#ifdef ENABLE_WALLET
b20c38cc 3414 if (VERUS_MINTBLOCKS && pwallet != NULL)
135fa24e 3415 {
3416 minerThreads->create_thread(boost::bind(&VerusStaker, pwallet));
3417 }
3418#endif
3419
e9e70b95 3420 for (int i = 0; i < nThreads; i++) {
8e8b6d70 3421#ifdef ENABLE_WALLET
855714b0 3422 minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet));
8e8b6d70 3423#else
855714b0 3424 minerThreads->create_thread(&BitcoinMiner_noeq);
8e8b6d70 3425#endif
e9e70b95 3426 }
8e8b6d70 3427 }
e9e70b95 3428
2cc0a252 3429#endif // ENABLE_MINING
This page took 1.266549 seconds and 4 git commands to generate.