]> Git Repo - VerusCoin.git/blob - src/miner.cpp
Improve testnet and PBaaS node connectivity
[VerusCoin.git] / src / miner.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
5
6 #include "miner.h"
7 #ifdef ENABLE_MINING
8 #include "pow/tromp/equi_miner.h"
9 #endif
10
11 #include "amount.h"
12 #include "chainparams.h"
13 #include "cc/StakeGuard.h"
14 #include "importcoin.h"
15 #include "consensus/consensus.h"
16 #include "consensus/upgrades.h"
17 #include "consensus/validation.h"
18 #ifdef ENABLE_MINING
19 #include "crypto/equihash.h"
20 #include "crypto/verus_hash.h"
21 #endif
22 #include "hash.h"
23 #include "key_io.h"
24 #include "main.h"
25 #include "metrics.h"
26 #include "net.h"
27 #include "pow.h"
28 #include "primitives/transaction.h"
29 #include "random.h"
30 #include "timedata.h"
31 #include "ui_interface.h"
32 #include "util.h"
33 #include "utilmoneystr.h"
34 #include "validationinterface.h"
35
36 #include "zcash/Address.hpp"
37 #include "transaction_builder.h"
38
39 #include "sodium.h"
40
41 #include <boost/thread.hpp>
42 #include <boost/tuple/tuple.hpp>
43 #ifdef ENABLE_MINING
44 #include <functional>
45 #endif
46 #include <mutex>
47
48 #include "pbaas/pbaas.h"
49 #include "pbaas/notarization.h"
50 #include "pbaas/identity.h"
51 #include "rpc/pbaasrpc.h"
52 #include "transaction_builder.h"
53
54 using namespace std;
55
56 //////////////////////////////////////////////////////////////////////////////
57 //
58 // BitcoinMiner
59 //
60
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 //
69 class COrphan
70 {
71 public:
72     const CTransaction* ptx;
73     set<uint256> setDependsOn;
74     CFeeRate feeRate;
75     double dPriority;
76     
77     COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
78     {
79     }
80 };
81
82 uint64_t nLastBlockTx = 0;
83 uint64_t nLastBlockSize = 0;
84
85 // We want to sort transactions by priority and fee rate, so:
86 typedef boost::tuple<double, CFeeRate, const CTransaction*> TxPriority;
87 class TxPriorityCompare
88 {
89     bool byFee;
90     
91 public:
92     TxPriorityCompare(bool _byFee) : byFee(_byFee) { }
93     
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
111 void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
112 {
113     pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
114
115     // Updating time can change work required on testnet:
116     if (consensusParams.nPowAllowMinDifficultyBlocksAfterHeight != boost::none) {
117         pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
118     }
119 }
120
121 #include "komodo_defs.h"
122
123 extern CCriticalSection cs_metrics;
124 extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
125 extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
126 extern bool VERUS_MINTBLOCKS;
127 extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
128 extern const char *ASSETCHAINS_ALGORITHMS[];
129 extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
130 extern uint32_t ASSETCHAINS_ALGO;
131 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
132 extern uint160 ASSETCHAINS_CHAINID;
133 extern uint160 VERUS_CHAINID;
134 extern std::string VERUS_CHAINNAME;
135 extern int32_t PBAAS_STARTBLOCK, PBAAS_ENDBLOCK;
136 extern string PBAAS_HOST, PBAAS_USERPASS, ASSETCHAINS_RPCHOST, ASSETCHAINS_RPCCREDENTIALS;;
137 extern int32_t PBAAS_PORT;
138 extern uint16_t ASSETCHAINS_RPCPORT;
139 extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY;
140 void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
141
142 extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33];
143 uint32_t Mining_start, Mining_height;
144 int32_t My_notaryid = -1;
145 int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
146 int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize);
147 int32_t komodo_baseid(char *origbase);
148 int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag);
149 int64_t komodo_block_unlocktime(uint32_t nHeight);
150 uint64_t komodo_commission(const CBlock *block);
151 int32_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);
152 int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits, arith_uint256 &hashResult, std::vector<unsigned char> &utxosig, CTxDestination &rewardDest);
153 int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33);
154
155 void 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
173     int solutionVersion = CConstVerusSolutionVector::activationHeight.ActiveVersion(nHeight);
174
175     if (solutionVersion >= CConstVerusSolutionVector::activationHeight.ACTIVATE_PBAAS_HEADER)
176     {
177         // coinbase should already be finalized in the new version
178         if (buildMerkle)
179         {
180             pblock->hashMerkleRoot = pblock->BuildMerkleTree();
181             pblock->SetPrevMMRRoot(ChainMerkleMountainView(chainActive.GetMMR(), pindexPrev->GetHeight()).GetRoot());
182             BlockMMRange mmRange(pblock->BuildBlockMMRTree());
183             BlockMMView mmView(mmRange);
184             pblock->SetBlockMMRRoot(mmView.GetRoot());
185             pblock->AddUpdatePBaaSHeader();
186         }
187
188         UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
189
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
192         if (solutionVersion >= CConstVerusSolutionVector::activationHeight.ACTIVATE_PBAAS && !pblock->IsVerusPOSBlock())
193         {
194             pblock->AddUpdatePBaaSHeader();
195
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
241 extern CWallet *pwalletMain;
242
243 CPubKey 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
297 CPubKey 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
308 // call a chain that we consider a notary chain, meaning we call its daemon, not the other way around,
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.
311 void ProcessNewImports(const uint160 &sourceChainID, CPBaaSNotarization &lastConfirmed, CUTXORef &lastConfirmedUTXO, uint32_t nHeight)
312 {
313     if (CConstVerusSolutionVector::GetVersionByHeight(nHeight) < CActivationHeight::ACTIVATE_PBAAS || 
314         CConstVerusSolutionVector::activationHeight.IsActivationHeight(CActivationHeight::ACTIVATE_PBAAS, nHeight))
315     {
316         return;
317     }
318
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();
323     uint160 thisChainID = thisChain.GetID();
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
331     // printf("%s: processing imports for %s\n", __func__, sourceChain.name.c_str());
332
333     bool isSameChain = thisChain.GetID() == sourceChainID;
334
335     CChainNotarizationData cnd;
336     if (!(GetNotarizationData(sourceChainID, cnd) && cnd.IsConfirmed()))
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;
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;
351     CAddressUnspentDbEntry foundEntry;
352     CCrossChainImport lastCCI;
353     std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>> exports;
354
355     {
356         LOCK(cs_main);
357
358         if (!isSameChain &&
359             lastConfirmed.proofRoots.count(sourceChainID) &&
360             GetAddressUnspent(CKeyID(CCrossChainRPCData::GetConditionID(sourceChainID, CCrossChainImport::CurrencySystemImportKey())), CScript::P2IDX, unspentOutputs))
361         {
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 && 
379                 lastCCI.sourceSystemHeight < lastConfirmed.notarizationHeight)
380             {
381                 UniValue params(UniValue::VARR);
382
383                 params.push_back(EncodeDestination(CIdentityID(thisChainID)));
384                 params.push_back((int64_t)lastCCI.sourceSystemHeight);
385                 params.push_back((int64_t)lastConfirmed.proofRoots[sourceChainID].rootHeight);
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                 }
410                 bool foundCurrent = false;
411                 for (int i = 0; i < result.size(); i++)
412                 {
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
424                     // create one import at a time
425                     uint32_t notarizationHeight = uni_get_int64(find_value(result[i], "height"));
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() &&
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))
448                     {
449                         /* printf("%s: proofRoot: %s, checkPartialRoot: %s, proofheight: %u, ischainproof: %s, blockhash: %s\n", 
450                             __func__,
451                             proofRootIt->second.ToUniValue().write(1,2).c_str(),
452                             txProof.CheckPartialTransaction(exportTx).GetHex().c_str(),
453                             txProof.GetProofHeight(),
454                             txProof.IsChainProof() ? "true" : "false",
455                             txProof.GetBlockHash().GetHex().c_str()); */
456                         printf("Invalid export for %s\n", uni_get_str(params[0]).c_str());
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                     }
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                     }
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                     {
487                         //printf("%s: onetransfer: %s\n", __func__, transferArrUni[j].write(1,2).c_str());
488                         oneExport.second.push_back(CReserveTransfer(transferArrUni[j]));
489                         if (!oneExport.second.back().IsValid())
490                         {
491                             printf("Invalid reserve transfers in export from %s\n", sourceChain.name.c_str());
492                             return;
493                         }
494                     }
495                     exports.push_back(oneExport);
496                 }
497             }
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;
510         }
511     }
512 }
513
514 bool 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
524 bool 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)
538     {
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
545 bool GetBlockOneLaunchNotarization(const CRPCChainData &notarySystem, 
546                                    const uint160 &currencyID,
547                                    CCurrencyDefinition &curDef,
548                                    CPBaaSNotarization &launchNotarization,
549                                    CPBaaSNotarization &notaryNotarization,
550                                    std::pair<CUTXORef, CPartialTransactionProof> &notarizationOutputProof,
551                                    std::pair<CUTXORef, CPartialTransactionProof> &exportOutputProof,
552                                    std::vector<CReserveTransfer> &exportTransfers)
553 {
554     UniValue result, error;
555     bool retVal = false;
556
557     UniValue params(UniValue::VARR);
558     params.push_back(EncodeDestination(CIdentityID(currencyID)));
559
560     // VRSC and VRSCTEST do not start with a notary chain
561     if (!IsVerusActive() && ConnectedChains.IsNotaryAvailable())
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.
566         if (CallNotary(notarySystem, "getlaunchinfo", params, result, error))
567         {
568             CCurrencyDefinition currency(find_value(result, "currencydefinition"));
569             CPBaaSNotarization notarization(find_value(result, "launchnotarization"));
570             notaryNotarization = CPBaaSNotarization(find_value(result, "notarynotarization"));
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"));
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             }
593             CUTXORef exportUtxo(uint256S(uni_get_str(find_value(result, "exporttxid"))), uni_get_int(find_value(result, "exportvoutnum")));
594
595             if (reject ||
596                 !currency.IsValid() ||
597                 !notarization.IsValid() ||
598                 !notarizationProof.IsValid() ||
599                 !notaryNotarization.IsValid())
600             {
601                 LogPrintf("%s: invalid launch notarization for currency %s\n", __func__, EncodeDestination(CIdentityID(currencyID)).c_str());
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(),
607                     notarizationProof.ToUniValue().write(1,2).c_str());
608             }
609             else
610             {
611                 //printf("%s: proofroot: %s\n", __func__, latestProofRoot.ToUniValue().write(1,2).c_str());
612                 curDef = currency;
613                 launchNotarization = notarization;
614                 launchNotarization.proofRoots = notaryNotarization.proofRoots;
615                 notaryNotarization.proofRoots[ASSETCHAINS_CHAINID] = CProofRoot::GetProofRoot(0);
616                 notaryNotarization.currencyStates[ASSETCHAINS_CHAINID] = launchNotarization.currencyState;
617                 notarizationOutputProof = std::make_pair(notarizationUtxo, notarizationProof);
618                 exportOutputProof = std::make_pair(exportUtxo, exportProof);
619                 retVal = true;
620             }
621         }
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         }
627     }
628     return retVal;
629 }
630
631 bool 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
650     // TODO: HARDENING - check the proof against the actual notarization here
651     if (!partialTxProof.IsValid() ||
652         partialTxProof.GetPartialTransaction(exportTx).IsNull() ||
653         partialTxProof.TransactionHash() != txId ||
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     {
660         //UniValue jsonTxOut(UniValue::VOBJ);
661         //TxToUniv(exportTx, uint256(), jsonTxOut);
662         //printf("%s: proofTxRoot:%s\npartialTx: %s\n", __func__, 
663         //                                            partialTxProof.GetPartialTransaction(exportTx).GetHex().c_str(),
664         //                                            jsonTxOut.write(1,2).c_str());
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
691 bool GetBlockOneImports(const CRPCChainData &notarySystem, const CPBaaSNotarization &launchNotarization, std::map<uint160, std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>>> &exports)
692 {
693     UniValue result, error;
694
695     UniValue params(UniValue::VARR);
696     params.push_back(EncodeDestination(CIdentityID(ASSETCHAINS_CHAINID)));
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     }
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;
719                 if (DecodeOneExport(result[i], ccx, oneExport))
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
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.
739 bool AddOneCurrencyImport(const CCurrencyDefinition &newCurrency, 
740                           const CPBaaSNotarization &lastNotarization,
741                           const std::pair<CUTXORef, CPartialTransactionProof> *pLaunchProof,
742                           const std::pair<CUTXORef, CPartialTransactionProof> *pFirstExport,
743                           const std::vector<CReserveTransfer> &_exportTransfers,
744                           CCurrencyValueMap &gatewayDeposits,
745                           std::vector<CTxOut> &outputs,
746                           CCurrencyValueMap &additionalFees)
747 {
748     uint160 newCurID = newCurrency.GetID();
749     CPBaaSNotarization newNotarization = lastNotarization;
750     newNotarization.prevNotarization = CUTXORef();
751     newNotarization.SetBlockOneNotarization();
752
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
760     // make a currency definition
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, 
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 &&
769         (newCurrency.IsFractional() ||
770         newCurrency.systemID == newCurID ||
771         (newCurrency.IsGateway() && newCurrency.GetID() == newCurrency.gatewayID))))
772     {
773         uint160 firstNotaryID = ConnectedChains.FirstNotaryChain().chainDefinition.GetID();
774
775         // first, put evidence of the notarization pre-import
776         int notarizationIdx = -1;
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);
789             notarizationIdx = outputs.size();
790             outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CNotaryEvidence>(EVAL_NOTARY_EVIDENCE, dests, 1, &evidence))));
791         }
792
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
804         if ((newCurrency.systemID == ASSETCHAINS_CHAINID) && firstNotaryID == newCurrency.launchSystemID)
805         {
806             uint256 transferHash;
807             std::vector<CTxOut> importOutputs;
808             CCurrencyValueMap importedCurrency, gatewayDepositsUsed, spentCurrencyOut;
809
810             CPBaaSNotarization tempLastNotarization = lastNotarization;
811             tempLastNotarization.currencyState.SetLaunchCompleteMarker(false);
812
813             std::vector<CReserveTransfer> exportTransfers(_exportTransfers);
814             if (!tempLastNotarization.NextNotarizationInfo(ConnectedChains.FirstNotaryChain().chainDefinition,
815                                                            newCurrency,
816                                                            0,
817                                                            1,
818                                                            exportTransfers,
819                                                            transferHash,
820                                                            newNotarization,
821                                                            importOutputs,
822                                                            importedCurrency,
823                                                            gatewayDepositsUsed,
824                                                            spentCurrencyOut))
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             }
831
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)
846             {
847                 additionalFees += (originalFees - liquidityFees);
848             }
849
850             newNotarization.SetBlockOneNotarization();
851
852             // display import outputs
853             CMutableTransaction debugTxOut;
854             debugTxOut.vout = outputs;
855             debugTxOut.vout.insert(debugTxOut.vout.end(), importOutputs.begin(), importOutputs.end());
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());
862
863             newNotarization.prevNotarization = CUTXORef();
864             newNotarization.prevHeight = 0;
865
866             // get the first export for launch from the notary chain
867             CTransaction firstExportTx;
868             if (!pFirstExport || !(pFirstExport->second.IsValid() && !pFirstExport->second.GetPartialTransaction(firstExportTx).IsNull()))
869             {
870                 LogPrintf("%s: invalid first export for PBaaS or converter launch\n");
871                 return false;
872             }
873
874             // get the export for this import
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             }
881
882             // create an import based on launch conditions that covers all pre-allocations and uses the initial notarization.
883             // generate outputs, then fill in numOutputs
884             CCrossChainImport cci = CCrossChainImport(newCurrency.launchSystemID,
885                                                       newNotarization.notarizationHeight,
886                                                       newCurID,
887                                                       ccx.totalAmounts,
888                                                       CCurrencyValueMap(),
889                                                       0,
890                                                       ccx.hashReserveTransfers,
891                                                       pFirstExport->first.hash,
892                                                       pFirstExport->first.n);
893             cci.SetSameChain(newCurrency.launchSystemID == ASSETCHAINS_CHAINID);
894             cci.SetPostLaunch();
895             cci.SetInitialLaunchImport();
896
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
900             /* printf("%s: ccx.totalAmounts: %s\ngatewayDepositsUsed: %s\nadditionalFees: %s\noriginalFees: %s\n",
901                 __func__,
902                 ccx.totalAmounts.ToUniValue().write(1,2).c_str(),
903                 gatewayDepositsUsed.ToUniValue().write(1,2).c_str(),
904                 additionalFees.ToUniValue().write(1,2).c_str(),
905                 originalFees.ToUniValue().write(1,2).c_str()); */
906
907             // to determine left over reserves for deposit, consider imported and emitted as the same
908             gatewayDeposits = CCurrencyValueMap(lastNotarization.currencyState.currencies, lastNotarization.currencyState.reserveIn);
909             if (!newCurrency.IsFractional())
910             {
911                 gatewayDeposits += originalFees;
912             }
913             gatewayDeposits.valueMap[newCurID] += newNotarization.currencyState.primaryCurrencyOut;
914
915             printf("importedcurrency %s\nspentcurrencyout %s\ngatewaydeposits %s\n", 
916                 importedCurrency.ToUniValue().write(1,2).c_str(),
917                 spentCurrencyOut.ToUniValue().write(1,2).c_str(),
918                 gatewayDeposits.ToUniValue().write(1,2).c_str());
919
920             gatewayDeposits = (gatewayDeposits - spentCurrencyOut).CanonicalMap();
921
922             printf("importedcurrency %s\nspentcurrencyout %s\nnewgatewaydeposits %s\n", 
923                 importedCurrency.ToUniValue().write(1,2).c_str(),
924                 spentCurrencyOut.ToUniValue().write(1,2).c_str(),
925                 gatewayDeposits.ToUniValue().write(1,2).c_str());
926
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);
935                 std::vector<CTxDestination> depositDests({CPubKey(ParseHex(depositCC.CChexstr))});
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
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
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
983             // add export before other outputs
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,
988                                                        CUTXORef(uint256(), notarizationIdx),
989                                                        true,
990                                                        std::map<CIdentityID, CIdentitySignature>(),
991                                                        std::vector<CPartialTransactionProof>({pFirstExport->second}),
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());
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
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             {
1020                 registrationAmount = 0;
1021             }
1022
1023             CCrossChainImport cci = CCrossChainImport(ConnectedChains.ThisChain().launchSystemID,
1024                                                       1,
1025                                                       newCurID,
1026                                                       CCurrencyValueMap());
1027             cci.SetDefinitionImport(true);
1028             outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCrossChainImport>(EVAL_CROSSCHAIN_IMPORT, dests, 1, &cci))));
1029
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             }
1041             outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CPBaaSNotarization>(EVAL_EARNEDNOTARIZATION, dests, 1, &newNotarization))));
1042
1043             CReserveTransactionDescriptor rtxd;
1044             CCoinbaseCurrencyState importState = newNotarization.currencyState;
1045             importState.RevertReservesAndSupply();
1046             CCurrencyValueMap importedCurrency;
1047             CCurrencyValueMap gatewayDepositsIn;
1048             CCurrencyValueMap spentCurrencyOut;
1049             CCoinbaseCurrencyState newCurrencyState;
1050             if (!rtxd.AddReserveTransferImportOutputs(ConnectedChains.FirstNotaryChain().chainDefinition,
1051                                                       ConnectedChains.ThisChain(),
1052                                                       newCurrency,
1053                                                       importState,
1054                                                       std::vector<CReserveTransfer>(),
1055                                                       outputs,
1056                                                       importedCurrency,
1057                                                       gatewayDepositsIn,
1058                                                       spentCurrencyOut,
1059                                                       &newCurrencyState))
1060             {
1061                 LogPrintf("Invalid starting currency import for %s\n", ConnectedChains.ThisChain().name.c_str());
1062                 printf("Invalid starting currency import for %s\n", ConnectedChains.ThisChain().name.c_str());
1063                 return false;
1064             }
1065         }
1066         // export thread
1067         cp = CCinit(&CC, EVAL_CROSSCHAIN_EXPORT);
1068         dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
1069         CCrossChainExport ccx;
1070
1071         ccx = CCrossChainExport(ASSETCHAINS_CHAINID, 1, 1, newCurrency.systemID, newCurID, 0, CCurrencyValueMap(), CCurrencyValueMap(), uint256());
1072         outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CCrossChainExport>(EVAL_CROSSCHAIN_EXPORT, dests, 1, &ccx))));
1073     }
1074     else
1075     {
1076         cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
1077         if (newCurID == ASSETCHAINS_CHAINID &&
1078             newCurrency.notarizationProtocol == newCurrency.NOTARIZATION_NOTARY_CHAINID)
1079         {
1080             dests = std::vector<CTxDestination>({CIdentityID(newCurID)});
1081         }
1082         else
1083         {
1084             dests = std::vector<CTxDestination>({CPubKey(ParseHex(CC.CChexstr))});
1085         }
1086         // we notarize our notary chain here, not ourselves
1087         if (newNotarization.currencyID == ASSETCHAINS_CHAINID)
1088         {
1089             if (!newNotarization.SetMirror())
1090             {
1091                 LogPrintf("Cannot mirror our notarization from notary chain\n");
1092                 printf("Cannot mirror our notarization from notary chain\n");
1093                 return false;
1094             }
1095         }
1096         newNotarization.SetBlockOneNotarization();
1097         outputs.push_back(CTxOut(0, MakeMofNCCScript(CConditionObj<CPBaaSNotarization>(EVAL_EARNEDNOTARIZATION, dests, 1, &newNotarization))));
1098     }
1099     return true;
1100 }
1101
1102 // create all special PBaaS outputs for block 1
1103 bool MakeBlockOneCoinbaseOutputs(std::vector<CTxOut> &outputs,
1104                                  CPBaaSNotarization &launchNotarization,
1105                                  CCurrencyValueMap &additionalFees,
1106                                  const Consensus::Params &consensusParams)
1107 {
1108     uint160 thisChainID = ConnectedChains.ThisChain().GetID();
1109     CCurrencyDefinition &thisChain = ConnectedChains.ThisChain();
1110     uint160 firstNotaryID = ConnectedChains.FirstNotaryChain().GetID();
1111     CCoinbaseCurrencyState currencyState;
1112     std::map<uint160, std::vector<std::pair<std::pair<CInputDescriptor, CPartialTransactionProof>, std::vector<CReserveTransfer>>>> blockOneExportImports;
1113
1114     std::pair<CUTXORef, CPartialTransactionProof> launchNotarizationProof;
1115     std::pair<CUTXORef, CPartialTransactionProof> launchExportProof;
1116     std::vector<CReserveTransfer> launchExportTransfers;
1117     CPBaaSNotarization notaryNotarization;
1118
1119     if (!GetBlockOneLaunchNotarization(ConnectedChains.FirstNotaryChain(), 
1120                                        thisChainID, 
1121                                        thisChain, 
1122                                        launchNotarization,
1123                                        notaryNotarization,
1124                                        launchNotarizationProof,
1125                                        launchExportProof,
1126                                        launchExportTransfers))
1127     {
1128         // cannot make block 1 unless we can get the initial currency state from the first notary system
1129         LogPrintf("Cannot find chain on notary system\n");
1130         printf("Cannot find chain on notary system\n");
1131         return false;
1132     }
1133
1134     // we need to have a launch decision to be able to mine any blocks, prior to launch being clear,
1135     // it is not an error. we are just not ready.
1136     if (!launchNotarization.IsLaunchCleared())
1137     {
1138         return false;
1139     }
1140
1141     if (!launchNotarization.IsLaunchConfirmed())
1142     {
1143         // we must reach minimums in all currencies to launch
1144         LogPrintf("This chain did not receive the minimum currency contributions and cannot launch. Pre-launch contributions to this chain can be refunded.\n");
1145         printf("This chain did not receive the minimum currency contributions and cannot launch. Pre-launch contributions to this chain can be refunded.\n");
1146         return false;
1147     }
1148
1149     // get initial imports
1150     if (!GetBlockOneImports(ConnectedChains.FirstNotaryChain(), launchNotarization, blockOneExportImports))
1151     {
1152         // we must reach minimums in all currencies to launch
1153         LogPrintf("Cannot retrieve initial export imports from notary system\n");
1154         printf("Cannot retrieve initial export imports from notary system\n");
1155         return false;
1156     }
1157
1158     // get all currencies/IDs that we will need to retrieve from our notary chain
1159     std::set<uint160> blockOneCurrencies;
1160     std::set<uint160> blockOneIDs = {ASSETCHAINS_CHAINID};
1161     std::set<uint160> convertersToCreate;
1162
1163     CPBaaSNotarization converterNotarization;
1164     std::pair<CUTXORef, CPartialTransactionProof> converterNotarizationProof;
1165     std::pair<CUTXORef, CPartialTransactionProof> converterExportProof;
1166     std::vector<CReserveTransfer> converterExportTransfers;
1167     uint160 converterCurrencyID = thisChain.GatewayConverterID();
1168     CCurrencyDefinition converterCurDef;
1169
1170     // if we have a converter currency, ensure that it also meets requirements for currency launch
1171     if (!thisChain.gatewayConverterName.empty())
1172     {
1173         if (!GetBlockOneLaunchNotarization(ConnectedChains.FirstNotaryChain(), 
1174                                            converterCurrencyID,
1175                                            converterCurDef,
1176                                            converterNotarization,
1177                                            notaryNotarization,
1178                                            converterNotarizationProof,
1179                                            converterExportProof,
1180                                            converterExportTransfers))
1181         {
1182             LogPrintf("Unable to get gateway converter initial state\n");
1183             printf("Unable to get gateway converter initial state\n");
1184             return false;
1185         }
1186
1187         notaryNotarization.currencyStates[converterCurrencyID] = converterNotarization.currencyState;
1188
1189         // both currency and primary gateway must have their pre-launch phase complete before we can make a decision
1190         // about launching
1191         if (!converterNotarization.IsLaunchCleared())
1192         {
1193             return false;
1194         }
1195
1196         // we need to have a cleared launch to be able to launch
1197         if (!converterNotarization.IsLaunchConfirmed())
1198         {
1199             LogPrintf("Primary currency met requirements for launch, but gateway currency converter did not\n");
1200             printf("Primary currency met requirements for launch, but gateway currency converter did not\n");
1201             return false;
1202         }
1203
1204         convertersToCreate.insert(converterCurrencyID);
1205     }
1206
1207     // Now, add block 1 imports, which provide a foundation of all IDs and currencies needed to launch the
1208     // new system, including ID and currency outputs for notary chain, all currencies we accept for pre-conversion,
1209     // native currency of system launching the chain.
1210     for (auto &oneNotary : ConnectedChains.notarySystems)
1211     {
1212         // first, we need to have the native notary currency itself and its notaries, if it has them
1213         blockOneCurrencies.insert(oneNotary.first);
1214         blockOneIDs.insert(oneNotary.second.notaryChain.chainDefinition.notaries.begin(), oneNotary.second.notaryChain.chainDefinition.notaries.end());
1215     }
1216
1217     for (auto &onePrealloc : thisChain.preAllocation)
1218     {
1219         blockOneIDs.insert(onePrealloc.first);
1220     }
1221
1222     // get this chain's notaries
1223     auto &notaryIDs = ConnectedChains.ThisChain().notaries;
1224     blockOneIDs.insert(notaryIDs.begin(), notaryIDs.end());
1225
1226     // now retrieve IDs and currencies
1227     std::map<uint160, std::pair<CCurrencyDefinition,CPBaaSNotarization>> currencyImports;
1228     std::map<uint160, CIdentity> identityImports;
1229     if (!ConnectedChains.GetNotaryCurrencies(ConnectedChains.FirstNotaryChain(), blockOneCurrencies, currencyImports) ||
1230         !ConnectedChains.GetNotaryIDs(ConnectedChains.FirstNotaryChain(), blockOneIDs, identityImports))
1231     {
1232         // we must reach minimums in all currencies to launch
1233         LogPrintf("Cannot retrieve identity and currency definitions needed to create block 1\n");
1234         printf("Cannot retrieve identity and currency definitions needed to create block 1\n");
1235         return false;
1236     }
1237
1238     if (currencyImports.count(notaryNotarization.currencyID))
1239     {
1240         currencyImports[notaryNotarization.currencyID].second = notaryNotarization;
1241     }
1242
1243     // add all imported currency and identity outputs, identity revocaton and recovery IDs must be explicitly imported if needed
1244     for (auto &oneIdentity : identityImports)
1245     {
1246         outputs.push_back(CTxOut(0, oneIdentity.second.IdentityUpdateOutputScript(1)));
1247     }
1248
1249     // calculate all issued currency on this chain for both the native and converter currencies,
1250     // which is the only currency that can be considered a gateway deposit at launch. this can
1251     // be used for native currency fee conversions
1252     CCurrencyValueMap gatewayDeposits;
1253
1254     bool success = AddOneCurrencyImport(thisChain, 
1255                                         launchNotarization,
1256                                         &launchNotarizationProof,
1257                                         &launchExportProof,
1258                                         launchExportTransfers,
1259                                         gatewayDeposits,
1260                                         outputs,
1261                                         additionalFees);
1262
1263     // now, the converter
1264     if (success && converterCurDef.IsValid())
1265     {
1266         // TODO: add a new ID for the converter currency, controlled by the same primary addresses as the
1267         // ID for this chain
1268         CCurrencyValueMap converterDeposits;
1269
1270         success = AddOneCurrencyImport(converterCurDef, 
1271                                        converterNotarization,
1272                                        &converterNotarizationProof,
1273                                        &converterExportProof,
1274                                        converterExportTransfers,
1275                                        converterDeposits,
1276                                        outputs,
1277                                        additionalFees);
1278     }
1279
1280     if (success)
1281     {
1282         currencyImports.erase(ASSETCHAINS_CHAINID);
1283         currencyImports.erase(converterCurrencyID);
1284         // now, add the rest of necessary currencies
1285         for (auto &oneCurrency : currencyImports)
1286         {
1287             success = AddOneCurrencyImport(oneCurrency.second.first, 
1288                                            oneCurrency.second.second,
1289                                            nullptr,
1290                                            nullptr,
1291                                            std::vector<CReserveTransfer>(),
1292                                            gatewayDeposits,
1293                                            outputs,
1294                                            additionalFees);
1295             if (!success)
1296             {
1297                 break;
1298             }
1299         }
1300     }
1301     return success;
1302 }
1303
1304 CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const std::vector<CTxOut> &minerOutputs, bool isStake)
1305 {
1306     // instead of one scriptPubKeyIn, we take a vector of them along with relative weight. each is assigned a percentage of the block subsidy and
1307     // mining reward based on its weight relative to the total
1308     if (!(minerOutputs.size() && ConnectedChains.SetLatestMiningOutputs(minerOutputs) || isStake))
1309     {
1310         fprintf(stderr,"%s: Must have valid miner outputs, including script with valid PK, PKH, or Verus ID destination.\n", __func__);
1311         return NULL;
1312     }
1313
1314     CTxDestination firstDestination;
1315
1316     if (minerOutputs.size())
1317     {
1318         int64_t shareCheck = 0;
1319         CTxDestination checkDest;
1320         for (auto &output : minerOutputs)
1321         {
1322             shareCheck += output.nValue;
1323             if (shareCheck < 0 || 
1324                 shareCheck > INT_MAX || 
1325                 !ExtractDestination(output.scriptPubKey, checkDest) || 
1326                 (checkDest.which() == COptCCParams::ADDRTYPE_INVALID))
1327             {
1328                 fprintf(stderr,"Invalid miner outputs share specifications\n");
1329                 return NULL;
1330             }
1331         }
1332         ExtractDestination(minerOutputs[0].scriptPubKey, firstDestination);
1333     }
1334
1335     uint32_t blocktime;
1336     //fprintf(stderr,"create new block\n");
1337     // Create new block
1338     std::unique_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
1339     if(!pblocktemplate.get())
1340     {
1341         fprintf(stderr,"pblocktemplate.get() failure\n");
1342         return NULL;
1343     }
1344     CBlock *pblock = &pblocktemplate->block; // pointer for convenience
1345
1346     pblock->nSolution.resize(Eh200_9.SolutionWidth);
1347
1348     pblock->SetVersionByHeight(chainActive.LastTip()->GetHeight() + 1);
1349
1350     // -regtest only: allow overriding block.nVersion with
1351     // -blockversion=N to test forking scenarios
1352     if (chainparams.MineBlocksOnDemand())
1353         pblock->nVersion = GetArg("-blockversion", pblock->nVersion);
1354     
1355     // Add dummy coinbase tx placeholder as first transaction
1356     pblock->vtx.push_back(CTransaction());
1357
1358     pblocktemplate->vTxFees.push_back(-1); // updated at end
1359     pblocktemplate->vTxSigOps.push_back(-1); // updated at end
1360     
1361     // Largest block you're willing to create:
1362     unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE);
1363
1364     // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
1365     nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
1366
1367     unsigned int nMaxIDSize = nBlockMaxSize / 2;
1368     unsigned int nCurrentIDSize = 0;
1369     
1370     // How much of the block should be dedicated to high-priority transactions,
1371     // included regardless of the fees they pay
1372     unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
1373     nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
1374     
1375     // Minimum block size you want to create; block will be filled with free transactions
1376     // until there are no more or the block reaches this size:
1377     unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE);
1378     nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
1379     
1380     // Collect memory pool transactions into the block
1381     CAmount nFees = 0;
1382     CAmount takenFees = 0;
1383
1384     bool isVerusActive = IsVerusActive();
1385     CCurrencyDefinition &thisChain = ConnectedChains.ThisChain();
1386
1387     std::vector<CAmount> exchangeRate(thisChain.currencies.size());
1388
1389     // we will attempt to spend any cheats we see
1390     CTransaction cheatTx;
1391     boost::optional<CTransaction> cheatSpend;
1392     uint256 cbHash;
1393
1394     CBlockIndex* pindexPrev = 0;
1395     bool loop = true;
1396     while (loop)
1397     {
1398         loop = false;
1399         int nHeight;
1400         const Consensus::Params &consensusParams = chainparams.GetConsensus();
1401         uint32_t consensusBranchId;
1402         int64_t nMedianTimePast = 0;
1403         uint32_t proposedTime = 0;
1404
1405         {
1406             while (proposedTime == nMedianTimePast)
1407             {
1408                 if (proposedTime)
1409                 {
1410                     MilliSleep(20);
1411                 }
1412                 LOCK(cs_main);
1413                 pindexPrev = chainActive.LastTip();
1414                 nHeight = pindexPrev->GetHeight() + 1;
1415                 consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
1416                 nMedianTimePast = pindexPrev->GetMedianTimePast();
1417                 proposedTime = GetAdjustedTime();
1418
1419                 if (proposedTime == nMedianTimePast)
1420                 {
1421                     boost::this_thread::interruption_point();
1422                 }
1423             }
1424         }
1425
1426         CCoinbaseCurrencyState currencyState;
1427         CCoinsViewCache view(pcoinsTip);
1428         uint32_t expired; uint64_t commission;
1429         
1430         SaplingMerkleTree sapling_tree;
1431
1432         {
1433             LOCK2(cs_main, mempool.cs);
1434             if (pindexPrev != chainActive.LastTip())
1435             {
1436                 // try again
1437                 loop = true;
1438                 continue;
1439             }
1440             pblock->nTime = GetAdjustedTime();
1441
1442             currencyState = ConnectedChains.GetCurrencyState(nHeight);
1443
1444             if (!(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree)))
1445             {
1446                 LogPrintf("%s: failed to get Sapling anchor\n", __func__);
1447                 assert(false);
1448             }
1449         }
1450
1451         // Priority order to process transactions
1452         list<COrphan> vOrphan; // list memory doesn't move
1453         map<uint256, vector<COrphan*> > mapDependers;
1454         bool fPrintPriority = GetBoolArg("-printpriority", false);
1455         
1456         // This vector will be sorted into a priority queue:
1457         vector<TxPriority> vecPriority;
1458         vecPriority.reserve(mempool.mapTx.size() + 1);
1459
1460         {
1461             LOCK(cs_main);
1462
1463             // check if we should add cheat transaction
1464             CBlockIndex *ppast;
1465             CTransaction cb;
1466             int cheatHeight = nHeight - COINBASE_MATURITY < 1 ? 1 : nHeight - COINBASE_MATURITY;
1467             if (defaultSaplingDest &&
1468                 chainActive.Height() > 100 && 
1469                 (ppast = chainActive[cheatHeight]) && 
1470                 ppast->IsVerusPOSBlock() && 
1471                 cheatList.IsHeightOrGreaterInList(cheatHeight))
1472             {
1473                 // get the block and see if there is a cheat candidate for the stake tx
1474                 CBlock b;
1475                 if (!(fHavePruned && !(ppast->nStatus & BLOCK_HAVE_DATA) && ppast->nTx > 0) && ReadBlockFromDisk(b, ppast, chainparams.GetConsensus(), 1))
1476                 {
1477                     CTransaction &stakeTx = b.vtx[b.vtx.size() - 1];
1478
1479                     if (cheatList.IsCheatInList(stakeTx, &cheatTx))
1480                     {
1481                         // make and sign the cheat transaction to spend the coinbase to our address
1482                         CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
1483
1484                         uint32_t voutNum;
1485                         // get the first vout with value
1486                         for (voutNum = 0; voutNum < b.vtx[0].vout.size(); voutNum++)
1487                         {
1488                             if (b.vtx[0].vout[voutNum].nValue > 0)
1489                                 break;
1490                         }
1491
1492                         // send to the same pub key as the destination of this block reward
1493                         if (MakeCheatEvidence(mtx, b.vtx[0], voutNum, cheatTx))
1494                         {
1495                             LOCK(pwalletMain->cs_wallet);
1496                             TransactionBuilder tb = TransactionBuilder(consensusParams, nHeight);
1497                             cb = b.vtx[0];
1498                             cbHash = cb.GetHash();
1499
1500                             bool hasInput = false;
1501                             for (uint32_t i = 0; i < cb.vout.size(); i++)
1502                             {
1503                                 // add the spends with the cheat
1504                                 if (cb.vout[i].nValue > 0)
1505                                 {
1506                                     tb.AddTransparentInput(COutPoint(cbHash,i), cb.vout[0].scriptPubKey, cb.vout[0].nValue);
1507                                     hasInput = true;
1508                                 }
1509                             }
1510
1511                             if (hasInput)
1512                             {
1513                                 // this is a send from a t-address to a sapling address, which we don't have an ovk for.
1514                                 // Instead, generate a common one from the HD seed. This ensures the data is
1515                                 // recoverable, at least for us, while keeping it logically separate from the ZIP 32
1516                                 // Sapling key hierarchy, which the user might not be using.
1517                                 uint256 ovk;
1518                                 HDSeed seed;
1519                                 if (pwalletMain->GetHDSeed(seed)) {
1520                                     ovk = ovkForShieldingFromTaddr(seed);
1521
1522                                     // send everything to Sapling address
1523                                     tb.SendChangeTo(defaultSaplingDest.value(), ovk);
1524
1525                                     tb.AddOpRet(mtx.vout[mtx.vout.size() - 1].scriptPubKey);
1526
1527                                     TransactionBuilderResult buildResult(tb.Build());
1528                                     if (!buildResult.IsError() && buildResult.IsTx())
1529                                     {
1530                                         cheatSpend = buildResult.GetTxOrThrow();
1531                                     }
1532                                     else
1533                                     {
1534                                         LogPrintf("Error building cheat catcher transaction: %s\n", buildResult.GetError().c_str());
1535                                     }
1536                                 }
1537                             }
1538                         }
1539                     }
1540                 }
1541             }
1542
1543             if (cheatSpend)
1544             {
1545                 LOCK(mempool.cs);
1546
1547                 cheatTx = cheatSpend.value();
1548                 std::list<CTransaction> removed;
1549                 mempool.removeConflicts(cheatTx, removed);
1550                 printf("Found cheating stake! Adding cheat spend for %.8f at block #%d, coinbase tx\n%s\n",
1551                     (double)cb.GetValueOut() / (double)COIN, nHeight, cheatSpend.value().vin[0].prevout.hash.GetHex().c_str());
1552
1553                 // add to mem pool and relay
1554                 if (myAddtomempool(cheatTx))
1555                 {
1556                     RelayTransaction(cheatTx);
1557                 }
1558             }
1559         }
1560
1561         //
1562         // Now start solving the block
1563         //
1564
1565         uint64_t nBlockSize = 1000;             // initial size
1566         uint64_t nBlockTx = 1;                  // number of transactions - always have a coinbase
1567         uint32_t autoTxSize = 0;                // extra transaction overhead that we will add while creating the block
1568         int nBlockSigOps = 100;
1569
1570         // VerusPoP staking transaction data
1571         CMutableTransaction txStaked;           // if this is a stake operation, the staking transaction that goes at the end
1572         uint32_t nStakeTxSize = 0;              // serialized size of the stake transaction
1573
1574         // if this is not for mining, first determine if we have a right to make a block
1575         if (isStake)
1576         {
1577             uint64_t txfees, utxovalue;
1578             uint32_t txtime;
1579             uint256 utxotxid;
1580             int32_t i, siglen, numsigs, utxovout;
1581             std::vector<unsigned char> utxosig;
1582
1583             txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight);
1584
1585             if (ASSETCHAINS_LWMAPOS != 0)
1586             {
1587                 uint32_t nBitsPOS;
1588                 arith_uint256 posHash;
1589
1590                 siglen = verus_staked(pblock, txStaked, nBitsPOS, posHash, utxosig, firstDestination);
1591                 blocktime = GetAdjustedTime();
1592             }
1593
1594             if (siglen <= 0)
1595             {
1596                 return NULL;
1597             }
1598
1599             pblock->nTime = blocktime;
1600             nStakeTxSize = GetSerializeSize(txStaked, SER_NETWORK, PROTOCOL_VERSION);
1601             nBlockSize += nStakeTxSize;
1602         }
1603
1604         ConnectedChains.AggregateChainTransfers(firstDestination, nHeight);
1605
1606         // Now the coinbase -
1607         // A PBaaS coinbase must have some additional outputs to enable certain chain state and functions to be properly
1608         // validated. All but currency state and the first chain definition are either optional or not valid on non-fractional reserve PBaaS blockchains
1609         // All of these are instant spend outputs that have no maturity wait time and may be spent in the same block.
1610         //
1611         // 1. (required) currency state - current state of currency supply and optionally reserve, premine, etc. This is primarily a data output to provide
1612         //    cross check for coin minting and burning operations, making it efficient to determine up-to-date supply, reserves, and conversions. To provide
1613         //    an extra level of supply cross-checking and fast data retrieval, this is part of all PBaaS chains' protocol, not just reserves.
1614         //    This output also includes reserve and native amounts for total conversions, less fees, of any conversions between Verus reserve and the
1615         //    native currency.
1616         //
1617         // 2. (block 1 required) chain definition - in order to confirm the amount of coins converted and issued within the possible range, before chain start,
1618         //    new PBaaS chains have a zero-amount, unspendable chain definition output.
1619         //
1620         // 3. (block 1 optional) initial import utxo - for any chain with conversion or pre-conversion, the first coinbase must include an initial import utxo. 
1621         //    Pre-conversions are handled on the launch chain before the PBaaS chain starts, so they are an additional output, which begins
1622         //    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
1623         //    are imported. All pre-converted outputs get their source currency from a thread that starts with this output in block 1.
1624         //
1625         // 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
1626         //    may have one, but currently, they can only be spent with valid exports, which only occur on reserve chains
1627         //
1628         // 5. (optional) notarization output - in order to ensure that notarization can occur independent of the availability of fungible
1629         //    coins on the network, and also that the notarization can provide a spendable finalization output and possible reward
1630         //
1631         // In addition, each PBaaS block can be mined with optional, fee-generating transactions. Inporting transactions from the reserve chain or sending
1632         // exported transactions to the reserve chain are optional fee-generating steps that would be easy to do when running multiple daemons.
1633         // The types of transactions miners/stakers may facilitate or create for fees are as follows:
1634         //
1635         // 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
1636         //
1637         // 2. Imported transactions from the export thread for this PBaaS chain on the Verus blockchain - imported transactions must spend the import utxo
1638         //    thread, represent the export from the alternate chain which spends the export output from the prior import transaction, carry a notary proof, and
1639         //    include outputs that map to each of its inputs on the source chain. Outputs can include unconverted reserve outputs only on fractional
1640         //    reserve chains, pre-converted outputs for any chain with launch conversion, and post launch outputs to be converted on fractional reserve
1641         //    chains. Each are handled in the following way:
1642         //      a. Unconverted outputs are left as outputs to the intended destination of Verus reserve token and do not pass through the coinbase
1643         //      b. Pre-converted outputs require that the import transaction spend the last pre-conversion output starting at block 1 as the source for
1644         //         pre-converted currency.
1645         //
1646         // 3. Zero or more aggregated exports that combine individual cross-chain transactions and reserve transfer outputs for export to the Verus chain. 
1647         //
1648         // 4. Conversion distribution transactions for all native and reserve currency conversions, including reserve transfer outputs without conversion as
1649         //    a second step for reserve transfers that have conversion included. Any remaining pre-converted reserve must always remain in a change output
1650         //    until it is exhausted
1651         CTxOut premineOut;
1652
1653         // size of conversion tx
1654         std::vector<CInputDescriptor> conversionInputs;
1655
1656         // if we are a PBaaS chain, first make sure we don't start prematurely, and if
1657         // we should make an earned notarization, make it and set index to non-zero value
1658         int32_t notarizationTxIndex = 0;                            // index of notarization if it is added
1659         int32_t conversionTxIndex = 0;                              // index of conversion transaction if it is added
1660
1661         // export transactions can be created here by aggregating all pending transfer requests and either getting 10 or more together, or
1662         // waiting n (10) blocks since the last one. each export must spend the output of the one before it
1663         std::vector<CMutableTransaction> exportTransactions;
1664
1665         // all transaction outputs requesting conversion to another currency (PBaaS fractional reserve only)
1666         // these will be used to calculate conversion price, fees, and generate coinbase conversion output as well as the
1667         // conversion output transaction
1668         std::vector<CTxOut> reserveConversionTo;
1669         std::vector<CTxOut> reserveConversionFrom;
1670
1671         int64_t pbaasTransparentIn = 0;
1672         int64_t pbaasTransparentOut = 0;
1673         //extern int64_t ASSETCHAINS_SUPPLY;
1674         //printf("%lu premine\n", ASSETCHAINS_SUPPLY);
1675         int64_t blockSubsidy = GetBlockSubsidy(nHeight, consensusParams);
1676
1677         uint160 thisChainID = ConnectedChains.ThisChain().GetID();
1678
1679         uint256 mmrRoot;
1680         vector<CInputDescriptor> notarizationInputs;
1681
1682         // used as scratch for making CCs, should be reinitialized each time
1683         CCcontract_info CC;
1684         CCcontract_info *cp;
1685         std::vector<CTxDestination> dests;
1686         CPubKey pkCC;
1687
1688         // Create coinbase tx and set up the null input with height
1689         CMutableTransaction coinbaseTx = CreateNewContextualCMutableTransaction(consensusParams, nHeight);
1690         coinbaseTx.vin.push_back(CTxIn(uint256(), (uint32_t)-1, CScript() << nHeight << OP_0));
1691
1692         // we will update amounts and fees later, but convert the guarded output now for validity checking and size estimate
1693         if (isStake)
1694         {
1695             // if there is a specific destination, use it
1696             CTransaction stakeTx(txStaked);
1697             CStakeParams p;
1698             if (ValidateStakeTransaction(stakeTx, p, false))
1699             {
1700                 if (p.Version() < p.VERSION_EXTENDED_STAKE && !p.pk.IsValid())
1701                 {
1702                     LogPrintf("CreateNewBlock: invalid public key\n");
1703                     fprintf(stderr,"CreateNewBlock: invalid public key\n");
1704                     return NULL;
1705                 }
1706                 CTxDestination guardedOutputDest = (p.Version() < p.VERSION_EXTENDED_STAKE) ? p.pk : p.delegate;
1707                 coinbaseTx.vout.push_back(CTxOut(1, CScript()));
1708                 if (!MakeGuardedOutput(1, guardedOutputDest, stakeTx, coinbaseTx.vout.back()))
1709                 {
1710                     LogPrintf("CreateNewBlock: failed to make GuardedOutput on staking coinbase\n");
1711                     fprintf(stderr,"CreateNewBlock: failed to make GuardedOutput on staking coinbase\n");
1712                     return NULL;
1713                 }
1714                 COptCCParams optP;
1715                 if (!coinbaseTx.vout.back().scriptPubKey.IsPayToCryptoCondition(optP) || !optP.IsValid())
1716                 {
1717                     MakeGuardedOutput(1, guardedOutputDest, stakeTx, coinbaseTx.vout.back());
1718                     LogPrintf("%s: created invalid staking coinbase\n", __func__);
1719                     fprintf(stderr,"%s: created invalid staking coinbase\n", __func__);
1720                     return NULL;
1721                 }
1722             }
1723             else
1724             {
1725                 LogPrintf("CreateNewBlock: invalid stake transaction\n");
1726                 fprintf(stderr,"CreateNewBlock: invalid stake transaction\n");
1727                 return NULL;
1728             }
1729         }
1730         else
1731         {
1732             // default outputs for mining and before stake guard or fee calculation
1733             // store the relative weight in the amount output to convert later to a relative portion
1734             // of the reward + fees
1735             coinbaseTx.vout.insert(coinbaseTx.vout.end(), minerOutputs.begin(), minerOutputs.end());
1736         }
1737
1738         CAmount totalEmission = blockSubsidy;
1739         CCurrencyValueMap additionalFees;
1740
1741         // if we don't have a connected root PBaaS chain, we can't properly check
1742         // and notarize the start block, so we have to pass the notarization and cross chain steps
1743         bool notaryConnected = ConnectedChains.IsNotaryAvailable();
1744
1745         // at block 1 for a PBaaS chain, we validate launch conditions
1746         if (!isVerusActive && nHeight == 1)
1747         {
1748             CPBaaSNotarization launchNotarization;
1749             if (!ConnectedChains.readyToStart &&
1750                 !ConnectedChains.CheckVerusPBaaSAvailable() &&
1751                 !ConnectedChains.readyToStart)
1752             {
1753                 return NULL;
1754             }
1755             if (!MakeBlockOneCoinbaseOutputs(coinbaseTx.vout, launchNotarization, additionalFees, Params().GetConsensus()))
1756             {
1757                 // can't mine block 1 if we are not connected to a notary
1758                 printf("%s: cannot create block one coinbase outputs\n", __func__);
1759                 LogPrintf("%s: cannot create block one coinbase outputs\n", __func__);
1760                 return NULL;
1761             }
1762             currencyState = launchNotarization.currencyState;
1763         }
1764
1765         // if we are a notary, notarize
1766         if (nHeight > CPBaaSNotarization::MIN_BLOCKS_BEFORE_NOTARY_FINALIZED && !VERUS_NOTARYID.IsNull())
1767         {
1768             CValidationState state;
1769             TransactionBuilder notarizationBuilder = TransactionBuilder(consensusParams, nHeight, pwalletMain);
1770             bool finalized;
1771             CTransaction notarizationTx;
1772             if (CPBaaSNotarization::ConfirmOrRejectNotarizations(pwalletMain, ConnectedChains.FirstNotaryChain(), state, notarizationBuilder, finalized))
1773             {
1774                 if (!notarizationBuilder.mtx.vin.size())
1775                 {
1776                     bool success = false;
1777                     CCurrencyValueMap reserveValueOut;
1778                     CAmount nativeValueOut;
1779                     // get a native currency input capable of paying a fee, and make our notary ID the change address
1780                     std::set<std::pair<const CWalletTx *, unsigned int>> setCoinsRet;
1781                     {
1782                         LOCK2(cs_main, pwalletMain->cs_wallet);
1783                         std::vector<COutput> vCoins;
1784                         if (IsVerusActive())
1785                         {
1786                             pwalletMain->AvailableCoins(vCoins,
1787                                                         false,
1788                                                         nullptr,
1789                                                         false,
1790                                                         true,
1791                                                         true,
1792                                                         true,
1793                                                         false);
1794                             success = pwalletMain->SelectCoinsMinConf(CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE, 0, 0, vCoins, setCoinsRet, nativeValueOut);
1795                             notarizationBuilder.SetFee(CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE);
1796                         }
1797                         else
1798                         {
1799                             CCurrencyValueMap totalTxFees;
1800                             totalTxFees.valueMap[ConnectedChains.FirstNotaryChain().chainDefinition.GetID()] = CPBaaSNotarization::DEFAULT_NOTARIZATION_FEE;
1801                             notarizationBuilder.SetReserveFee(totalTxFees);
1802                             notarizationBuilder.SetFee(0);
1803                             pwalletMain->AvailableReserveCoins(vCoins,
1804                                                                false,
1805                                                                nullptr,
1806                                                                true,
1807                                                                true,
1808                                                                nullptr,
1809                                                                &totalTxFees, 
1810                                                                false);
1811
1812                             success = pwalletMain->SelectReserveCoinsMinConf(totalTxFees,
1813                                                                             0,
1814                                                                             0,
1815                                                                             1,
1816                                                                             vCoins,
1817                                                                             setCoinsRet,
1818                                                                             reserveValueOut,
1819                                                                             nativeValueOut);
1820                         }
1821                     }
1822                     for (auto &oneInput : setCoinsRet)
1823                     {
1824                         notarizationBuilder.AddTransparentInput(COutPoint(oneInput.first->GetHash(), oneInput.second), 
1825                                                                 oneInput.first->vout[oneInput.second].scriptPubKey,
1826                                                                 oneInput.first->vout[oneInput.second].nValue);
1827                     }
1828                     notarizationBuilder.SendChangeTo(CTxDestination(VERUS_NOTARYID));
1829                 }
1830                 else
1831                 {
1832                     notarizationBuilder.SetFee(0);
1833                 }
1834
1835                 if (notarizationBuilder.mtx.vin.size())
1836                 {
1837                     LOCK2(cs_main, mempool.cs);
1838                     TransactionBuilderResult buildResult = notarizationBuilder.Build();
1839                     if (buildResult.IsTx())
1840                     {
1841                         notarizationTx = buildResult.GetTxOrThrow();
1842
1843                         UniValue jsonNotaryConfirmations(UniValue::VOBJ);
1844                         TxToUniv(notarizationTx, uint256(), jsonNotaryConfirmations);
1845                         //printf("%s: (PII) Submitting notarization confirmations:\n%s\n", __func__, jsonNotaryConfirmations.write(1,2).c_str());
1846                         LogPrintf("%s: (PII) Submitting notarization confirmations:\n%s\n", __func__, jsonNotaryConfirmations.write(1,2).c_str());
1847
1848                         // add to mem pool and relay
1849                         if (myAddtomempool(notarizationTx))
1850                         {
1851                             RelayTransaction(notarizationTx);
1852                         }
1853                     }
1854                     else
1855                     {
1856                         printf("%s: (PII) error adding notary evidence: %s\n", __func__, buildResult.GetError().c_str());
1857                         LogPrintf("%s: (PII) error adding notary evidence: %s\n", __func__, buildResult.GetError().c_str());
1858                     }
1859                 }
1860             }
1861         }
1862
1863         if (notaryConnected)
1864         {
1865             // if we should make an earned notarization, do so
1866             if (nHeight != 1 && !(VERUS_NOTARYID.IsNull() && VERUS_DEFAULTID.IsNull() && VERUS_NODEID.IsNull()))
1867             {
1868                 CIdentityID proposer = VERUS_NOTARYID.IsNull() ? (VERUS_DEFAULTID.IsNull() ? VERUS_NODEID : VERUS_DEFAULTID) : VERUS_NOTARYID;
1869
1870                 // if we have access to our notary daemon
1871                 // create a notarization if we would qualify to do so. add it to the mempool and next block
1872                 ChainMerkleMountainView mmv = chainActive.GetMMV();
1873                 mmrRoot = mmv.GetRoot();
1874                 int32_t confirmedInput = -1;
1875                 CTxDestination confirmedDest;
1876                 CValidationState state;
1877                 CPBaaSNotarization earnedNotarization;
1878
1879                 if (CPBaaSNotarization::CreateEarnedNotarization(ConnectedChains.FirstNotaryChain(),
1880                                                                  DestinationToTransferDestination(proposer),
1881                                                                  state,
1882                                                                  coinbaseTx.vout,
1883                                                                  earnedNotarization))
1884                 {
1885                 }
1886                 CPBaaSNotarization lastImportNotarization;
1887                 CUTXORef lastImportNotarizationUTXO;
1888
1889                 CPBaaSNotarization::SubmitFinalizedNotarizations(ConnectedChains.FirstNotaryChain(), state);
1890                 ProcessNewImports(ConnectedChains.FirstNotaryChain().chainDefinition.GetID(), lastImportNotarization, lastImportNotarizationUTXO, nHeight);
1891             }
1892         }
1893
1894         // done calling out, take locks for the rest
1895         LOCK2(cs_main, mempool.cs);
1896
1897         totalEmission = GetBlockSubsidy(nHeight, consensusParams);
1898         blockSubsidy = totalEmission;
1899
1900         // PBaaS chain's block 1 currency state is done by the time we get here,
1901         // including pre-allocations, etc.
1902         if (isVerusActive || nHeight != 1)
1903         {
1904             currencyState.UpdateWithEmission(totalEmission);
1905         }
1906
1907         // process any imports from the current chain to itself
1908         ConnectedChains.ProcessLocalImports();
1909
1910         CFeePool feePool;
1911         if (!CFeePool::GetCoinbaseFeePool(feePool, nHeight - 1) ||
1912             (!feePool.IsValid() && CConstVerusSolutionVector::GetVersionByHeight(nHeight - 1) >= CActivationHeight::ACTIVATE_PBAAS))
1913         {
1914             // we should be able to get a valid currency state, if not, fail
1915             LogPrintf("Failure to get fee pool information for blockchain height #%d\n", nHeight - 1);
1916             printf("Failure to get fee pool information for blockchain height #%d\n", nHeight - 1);
1917             return NULL;
1918         }
1919
1920         uint32_t solutionVersion = CConstVerusSolutionVector::GetVersionByHeight(nHeight);
1921         if (solutionVersion >= CActivationHeight::ACTIVATE_PBAAS && !feePool.IsValid())
1922         {
1923             // first block with a fee pool, so make it valid and empty
1924             feePool = CFeePool();
1925         }
1926
1927         // coinbase should have all necessary outputs
1928         uint32_t nCoinbaseSize = GetSerializeSize(coinbaseTx, SER_NETWORK, PROTOCOL_VERSION);
1929         nBlockSize += nCoinbaseSize;
1930
1931         // now create the priority array, including market order reserve transactions, since they can always execute, leave limits for later
1932         bool haveReserveTransactions = false;
1933         uint32_t reserveExchangeLimitSize = 0;
1934         std::vector<CReserveTransactionDescriptor> limitOrders;
1935
1936         // now add transactions from the mem pool to the priority heap
1937         for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
1938              mi != mempool.mapTx.end(); ++mi)
1939         {
1940             const CTransaction& tx = mi->GetTx();
1941             uint256 hash = tx.GetHash();
1942             
1943             int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST)
1944             ? nMedianTimePast
1945             : pblock->GetBlockTime();
1946
1947             if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, nLockTimeCutoff) || IsExpiredTx(tx, nHeight))
1948             {
1949                 //fprintf(stderr,"coinbase.%d finaltx.%d expired.%d\n",tx.IsCoinBase(),IsFinalTx(tx, nHeight, nLockTimeCutoff),IsExpiredTx(tx, nHeight));
1950                 continue;
1951             }
1952
1953             if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,nHeight,(uint32_t)pblock->nTime,0) < 0 )
1954             {
1955                 //fprintf(stderr,"CreateNewBlock: komodo_validate_interest failure nHeight.%d nTime.%u vs locktime.%u\n",nHeight,(uint32_t)pblock->nTime,(uint32_t)tx.nLockTime);
1956                 continue;
1957             }
1958
1959             COrphan* porphan = NULL;
1960             double dPriority = 0;
1961             CAmount nTotalIn = 0;
1962             CCurrencyValueMap totalReserveIn;
1963             bool fMissingInputs = false;
1964             CReserveTransactionDescriptor rtxd;
1965             bool isReserve = mempool.IsKnownReserveTransaction(hash, rtxd);
1966
1967             if (tx.IsCoinImport())
1968             {
1969                 CAmount nValueIn = GetCoinImportValue(tx);
1970                 nTotalIn += nValueIn;
1971                 dPriority += (double)nValueIn * 1000;  // flat multiplier
1972             } else {
1973                 if (isReserve)
1974                 {
1975                     nTotalIn += rtxd.nativeIn;
1976                     totalReserveIn = rtxd.ReserveInputMap();
1977                     assert(!totalReserveIn.valueMap.count(ASSETCHAINS_CHAINID));
1978                     if (rtxd.IsIdentity() && CNameReservation(tx).IsValid())
1979                     {
1980                         nCurrentIDSize += GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
1981                         if (nCurrentIDSize > nMaxIDSize)
1982                         {
1983                             continue;
1984                         }
1985                     }
1986                 }
1987                 BOOST_FOREACH(const CTxIn& txin, tx.vin)
1988                 {
1989                     CAmount nValueIn = 0;
1990                     CCurrencyValueMap reserveValueIn;
1991
1992                     // Read prev transaction
1993                     if (!view.HaveCoins(txin.prevout.hash))
1994                     {
1995                         // This should never happen; all transactions in the memory
1996                         // pool should connect to either transactions in the chain
1997                         // or other transactions in the memory pool.
1998                         if (!mempool.mapTx.count(txin.prevout.hash))
1999                         {
2000                             LogPrintf("ERROR: mempool transaction missing input\n");
2001                             if (fDebug) assert("mempool transaction missing input" == 0);
2002                             fMissingInputs = true;
2003                             if (porphan)
2004                                 vOrphan.pop_back();
2005                             break;
2006                         }
2007
2008                         // Has to wait for dependencies
2009                         if (!porphan)
2010                         {
2011                             // Use list for automatic deletion
2012                             vOrphan.push_back(COrphan(&tx));
2013                             porphan = &vOrphan.back();
2014                         }
2015                         mapDependers[txin.prevout.hash].push_back(porphan);
2016                         porphan->setDependsOn.insert(txin.prevout.hash);
2017
2018                         const CTransaction &otx = mempool.mapTx.find(txin.prevout.hash)->GetTx();
2019                         // consider reserve outputs and set priority according to their value here as well
2020                         if (isReserve)
2021                         {
2022                             totalReserveIn += otx.vout[txin.prevout.n].ReserveOutValue();
2023                         }
2024                         nTotalIn += otx.vout[txin.prevout.n].nValue;
2025                         continue;
2026                     }
2027                     const CCoins* coins = view.AccessCoins(txin.prevout.hash);
2028                     assert(coins);
2029
2030                     if (isReserve)
2031                     {
2032                         reserveValueIn = coins->vout[txin.prevout.n].ReserveOutValue();
2033                     }
2034
2035                     nValueIn = coins->vout[txin.prevout.n].nValue;
2036                     int nConf = nHeight - coins->nHeight;
2037
2038                     dPriority += ((double)((reserveValueIn.valueMap.size() ? currencyState.ReserveToNative(reserveValueIn) : 0) + nValueIn)) * nConf;
2039
2040                     if (!isReserve)
2041                     {
2042                         nTotalIn += nValueIn;
2043                         totalReserveIn += reserveValueIn;
2044                     }
2045                 }
2046                 nTotalIn += tx.GetShieldedValueIn();
2047             }
2048
2049             if (fMissingInputs) continue;
2050             
2051             // Priority is sum(valuein * age) / modified_txsize
2052             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
2053             dPriority = tx.ComputePriority(dPriority, nTxSize);
2054             
2055             CAmount nDeltaValueIn = nTotalIn + (totalReserveIn.valueMap.size() ? currencyState.ReserveToNative(totalReserveIn) : 0);
2056             CAmount nFeeValueIn = nDeltaValueIn;
2057             mempool.ApplyDeltas(hash, dPriority, nDeltaValueIn);
2058
2059             CAmount nativeEquivalentOut = 0;
2060
2061             // if there is reserve in, or this is a reserveexchange transaction, calculate fee properly
2062             if (isReserve && rtxd.ReserveOutputMap().valueMap.size())
2063             {
2064                 // if this has reserve currency out, convert it to native currency for fee calculation
2065                 nativeEquivalentOut = currencyState.ReserveToNative(rtxd.ReserveOutputMap());
2066             }
2067
2068             CFeeRate feeRate(isReserve ? rtxd.AllFeesAsNative(currencyState) + currencyState.ReserveToNative(rtxd.ReserveConversionFeesMap()) + rtxd.nativeConversionFees : 
2069                                          nFeeValueIn - (tx.GetValueOut() + nativeEquivalentOut), nTxSize);
2070
2071             if (porphan)
2072             {
2073                 porphan->dPriority = dPriority;
2074                 porphan->feeRate = feeRate;
2075             }
2076             else
2077                 vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
2078         }
2079
2080         //
2081         // NOW -- REALLY START TO FILL THE BLOCK
2082         //
2083         // estimate number of conversions, staking transaction size, and additional coinbase outputs that will be required
2084
2085         int32_t maxPreLimitOrderBlockSize = nBlockMaxSize - std::min(nBlockMaxSize >> 2, reserveExchangeLimitSize);
2086
2087         int64_t interest;
2088         bool fSortedByFee = (nBlockPrioritySize <= 0);
2089
2090         TxPriorityCompare comparer(fSortedByFee);
2091         std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
2092
2093         std::vector<int> reservePositions;
2094
2095         // now loop and fill the block, leaving space for reserve exchange limit transactions
2096         while (!vecPriority.empty())
2097         {
2098             // Take highest priority transaction off the priority queue:
2099             double dPriority = vecPriority.front().get<0>();
2100             CFeeRate feeRate = vecPriority.front().get<1>();
2101             const CTransaction& tx = *(vecPriority.front().get<2>());
2102             
2103             std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
2104             vecPriority.pop_back();
2105             
2106             // Size limits
2107             unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
2108             if (nBlockSize + nTxSize >= maxPreLimitOrderBlockSize - autoTxSize) // room for extra autotx
2109             {
2110                 //fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d maxPreLimitOrderBlockSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)maxPreLimitOrderBlockSize);
2111                 continue;
2112             }
2113             
2114             // Legacy limits on sigOps:
2115             unsigned int nTxSigOps = GetLegacySigOpCount(tx);
2116             if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
2117             {
2118                 //fprintf(stderr,"A nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
2119                 continue;
2120             }
2121             // Skip free transactions if we're past the minimum block size:
2122             const uint256& hash = tx.GetHash();
2123             double dPriorityDelta = 0;
2124             CAmount nFeeDelta = 0;
2125             mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta);
2126             if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
2127             {
2128                 //fprintf(stderr,"fee rate skip\n");
2129                 continue;
2130             }
2131
2132             // Prioritise by fee once past the priority size or we run out of high-priority
2133             // transactions:
2134             if (!fSortedByFee &&
2135                 ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority)))
2136             {
2137                 fSortedByFee = true;
2138                 comparer = TxPriorityCompare(fSortedByFee);
2139                 std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
2140             }
2141             
2142             if (!view.HaveInputs(tx))
2143             {
2144                 //fprintf(stderr,"dont have inputs\n");
2145                 continue;
2146             }
2147             CAmount nTxFees;
2148             CReserveTransactionDescriptor txDesc;
2149             bool isReserve = mempool.IsKnownReserveTransaction(hash, txDesc);
2150
2151             nTxFees = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime) - tx.GetValueOut();
2152             
2153             nTxSigOps += GetP2SHSigOpCount(tx, view);
2154             if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1)
2155             {
2156                 //fprintf(stderr,"B nBlockSigOps %d + %d nTxSigOps >= %d MAX_BLOCK_SIGOPS-1\n",(int32_t)nBlockSigOps,(int32_t)nTxSigOps,(int32_t)MAX_BLOCK_SIGOPS);
2157                 continue;
2158             }
2159
2160             // Note that flags: we don't want to set mempool/IsStandard()
2161             // policy here, but we still have to ensure that the block we
2162             // create only contains transactions that are valid in new blocks.
2163             CValidationState state;
2164             PrecomputedTransactionData txdata(tx);
2165             if (!ContextualCheckInputs(tx, state, view, nHeight, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
2166             {
2167                 //fprintf(stderr,"context failure\n");
2168                 continue;
2169             }
2170
2171             UpdateCoins(tx, view, nHeight);
2172
2173             if (isReserve)
2174             {
2175                 reservePositions.push_back(nBlockTx);
2176                 haveReserveTransactions = true;
2177                 additionalFees += txDesc.ReserveFees();
2178             }
2179
2180             BOOST_FOREACH(const OutputDescription &outDescription, tx.vShieldedOutput) {
2181                 sapling_tree.append(outDescription.cm);
2182             }
2183
2184             // Added
2185             pblock->vtx.push_back(tx);
2186             pblocktemplate->vTxFees.push_back(nTxFees);
2187             pblocktemplate->vTxSigOps.push_back(nTxSigOps);
2188             nBlockSize += nTxSize;
2189             ++nBlockTx;
2190             nBlockSigOps += nTxSigOps;
2191             nFees += nTxFees;
2192             if (fPrintPriority)
2193             {
2194                 LogPrintf("priority %.1f fee %s txid %s\n",dPriority, feeRate.ToString(), tx.GetHash().ToString());
2195             }
2196             
2197             // Add transactions that depend on this one to the priority queue
2198             if (mapDependers.count(hash))
2199             {
2200                 BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
2201                 {
2202                     if (!porphan->setDependsOn.empty())
2203                     {
2204                         porphan->setDependsOn.erase(hash);
2205                         if (porphan->setDependsOn.empty())
2206                         {
2207                             vecPriority.push_back(TxPriority(porphan->dPriority, porphan->feeRate, porphan->ptx));
2208                             std::push_heap(vecPriority.begin(), vecPriority.end(), comparer);
2209                         }
2210                     }
2211                 }
2212             }
2213         }
2214
2215         // first calculate and distribute block rewards, including fees in the minerOutputs vector
2216         CAmount rewardTotalShareAmount = 0;
2217         CAmount rewardFees = nFees;
2218         if (additionalFees.valueMap.count(thisChainID))
2219         {
2220             rewardFees += additionalFees.valueMap[thisChainID];
2221             additionalFees.valueMap.erase(thisChainID);
2222         }
2223
2224         CAmount verusFees = 0;
2225         if (VERUS_CHAINID != ASSETCHAINS_CHAINID && additionalFees.valueMap.count(VERUS_CHAINID))
2226         {
2227             verusFees += additionalFees.valueMap[VERUS_CHAINID];
2228             additionalFees.valueMap.erase(VERUS_CHAINID);
2229         }
2230
2231         if (additionalFees.valueMap.size())
2232         {
2233             printf("%s: burning reserve currency: %s\n", __func__, additionalFees.ToUniValue().write(1,2).c_str());
2234         }
2235
2236         if (feePool.IsValid())
2237         {
2238             // we support only the current native currency or VRSC on PBaaS chains in the fee pool for now
2239             feePool.reserveValues.valueMap[thisChainID] += rewardFees;
2240             if (verusFees)
2241             {
2242                 feePool.reserveValues.valueMap[VERUS_CHAINID] += verusFees;
2243             }
2244             CFeePool oneFeeShare = feePool.OneFeeShare();
2245             rewardFees = oneFeeShare.reserveValues.valueMap[thisChainID];
2246             feePool.reserveValues.valueMap[thisChainID] -= rewardFees;
2247
2248             if (VERUS_CHAINID != ASSETCHAINS_CHAINID && oneFeeShare.reserveValues.valueMap.count(VERUS_CHAINID))
2249             {
2250                 verusFees = oneFeeShare.reserveValues.valueMap[VERUS_CHAINID];
2251                 feePool.reserveValues.valueMap[VERUS_CHAINID] -= verusFees;
2252             }
2253
2254             cp = CCinit(&CC, EVAL_FEE_POOL);
2255             pkCC = CPubKey(ParseHex(CC.CChexstr));
2256             coinbaseTx.vout.push_back(CTxOut(0,MakeMofNCCScript(CConditionObj<CFeePool>(EVAL_FEE_POOL,{pkCC.GetID()},1,&feePool))));
2257         }
2258
2259         // printf("%s: rewardfees: %ld, verusfees: %ld\n", __func__, rewardFees, verusFees);
2260
2261         CAmount rewardTotal = blockSubsidy + rewardFees;
2262
2263         // now that we have the total reward, update the coinbase outputs
2264         if (isStake)
2265         {
2266             // TODO: need to add reserve output to stake coinbase to prevent burning of VRSC
2267             coinbaseTx.vout[0].nValue = rewardTotal;
2268         }
2269         else
2270         {
2271             for (auto &outputShare : minerOutputs)
2272             {
2273                 rewardTotalShareAmount += outputShare.nValue;
2274             }
2275
2276             int cbOutIdx;
2277             CAmount rewardLeft = rewardTotal;
2278             CAmount verusFeeLeft = verusFees;
2279             for (cbOutIdx = 0; cbOutIdx < minerOutputs.size(); cbOutIdx++)
2280             {
2281                 CAmount amount = (arith_uint256(rewardTotal) * arith_uint256(minerOutputs[cbOutIdx].nValue) / arith_uint256(rewardTotalShareAmount)).GetLow64();
2282                 if (rewardLeft <= amount || (cbOutIdx + 1) == minerOutputs.size())
2283                 {
2284                     amount = rewardLeft;
2285                 }
2286                 rewardLeft -= amount;
2287
2288                 // now make outputs for non-native, VRSC fees
2289                 if (verusFeeLeft)
2290                 {
2291                     CAmount verusFee = (arith_uint256(verusFees) * arith_uint256(minerOutputs[cbOutIdx].nValue) / arith_uint256(rewardTotalShareAmount)).GetLow64();
2292                     if (verusFeeLeft <= verusFee || (cbOutIdx + 1) == minerOutputs.size())
2293                     {
2294                         verusFee = verusFeeLeft;
2295                     }
2296                     CTxDestination minerDestination;
2297                     if (verusFee >= CFeePool::MIN_SHARE_SIZE && ExtractDestination(coinbaseTx.vout[cbOutIdx].scriptPubKey, minerDestination))
2298                     {
2299                         CTokenOutput to = CTokenOutput(VERUS_CHAINID, verusFee);
2300                         coinbaseTx.vout[cbOutIdx].scriptPubKey = MakeMofNCCScript(CConditionObj<CTokenOutput>(EVAL_RESERVE_OUTPUT, 
2301                                                                                   std::vector<CTxDestination>({minerDestination}),
2302                                                                                   1,
2303                                                                                   &to));
2304                     }
2305                     verusFeeLeft -= verusFee;
2306                 }
2307
2308                 // we had to wait to update this here to ensure it represented a correct distribution ratio
2309                 coinbaseTx.vout[cbOutIdx].nValue = amount;
2310             }
2311         }
2312
2313         nLastBlockTx = nBlockTx;
2314         nLastBlockSize = nBlockSize;
2315
2316         blocktime = std::max(pindexPrev->GetMedianTimePast(), GetAdjustedTime());
2317
2318         pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
2319
2320         coinbaseTx.nExpiryHeight = 0;
2321         coinbaseTx.nLockTime = blocktime;
2322
2323         // finalize input of coinbase
2324         coinbaseTx.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(0)) + COINBASE_FLAGS;
2325         assert(coinbaseTx.vin[0].scriptSig.size() <= 100);
2326
2327         // coinbase is done
2328         pblock->vtx[0] = coinbaseTx;
2329         uint256 cbHash = coinbaseTx.GetHash();
2330
2331         // display it at block 1 for PBaaS debugging
2332         /* if (nHeight == 1)
2333         {
2334             UniValue jsonTxOut(UniValue::VOBJ);
2335             TxToUniv(coinbaseTx, uint256(), jsonTxOut);
2336             printf("%s: new coinbase transaction: %s\n", __func__, jsonTxOut.write(1,2).c_str());
2337         } */
2338
2339         // if there is a stake transaction, add it to the very end
2340         if (isStake)
2341         {
2342             UpdateCoins(txStaked, view, nHeight);
2343             pblock->vtx.push_back(txStaked);
2344             pblocktemplate->vTxFees.push_back(0);
2345             int txSigOps = GetLegacySigOpCount(txStaked);
2346             pblocktemplate->vTxSigOps.push_back(txSigOps);
2347             // already added to the block size above
2348             ++nBlockTx;
2349             nBlockSigOps += txSigOps;
2350         }
2351
2352         extern CWallet *pwalletMain;
2353
2354         pblock->vtx[0] = coinbaseTx;
2355         pblocktemplate->vTxFees[0] = -nFees;
2356         pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
2357
2358         // if not Verus stake, setup nonce, otherwise, leave it alone
2359         if (!isStake || ASSETCHAINS_LWMAPOS == 0)
2360         {
2361             // Randomize nonce
2362             arith_uint256 nonce = UintToArith256(GetRandHash());
2363
2364             // Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters)
2365             nonce <<= ASSETCHAINS_NONCESHIFT[ASSETCHAINS_ALGO];
2366             nonce >>= 16;
2367             pblock->nNonce = ArithToUint256(nonce);
2368         }
2369         
2370         // Fill in header
2371         pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
2372         pblock->hashFinalSaplingRoot   = sapling_tree.root();
2373
2374         // all Verus PoS chains need this data in the block at all times
2375         if ( ASSETCHAINS_LWMAPOS || ASSETCHAINS_SYMBOL[0] == 0 || ASSETCHAINS_STAKED == 0 || KOMODO_MININGTHREADS > 0 )
2376         {
2377             UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
2378             pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus());
2379         }
2380
2381         if ( ASSETCHAINS_SYMBOL[0] == 0 && IS_KOMODO_NOTARY != 0 && My_notaryid >= 0 )
2382         {
2383             uint32_t r;
2384             CMutableTransaction txNotary = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1);
2385             if ( pblock->nTime < pindexPrev->nTime+60 )
2386                 pblock->nTime = pindexPrev->nTime + 60;
2387
2388             if ( komodo_notaryvin(txNotary,NOTARY_PUBKEY33) > 0 )
2389             {
2390                 CAmount txfees = 5000;
2391                 pblock->vtx.push_back(txNotary);
2392                 pblocktemplate->vTxFees.push_back(txfees);
2393                 pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txNotary));
2394                 nFees += txfees;
2395                 pblocktemplate->vTxFees[0] = -nFees;
2396                 //*(uint64_t *)(&pblock->vtx[0].vout[0].nValue) += txfees;
2397                 //fprintf(stderr,"added notaryvin\n");
2398             }
2399             else
2400             {
2401                 fprintf(stderr,"error adding notaryvin, need to create 0.0001 utxos\n");
2402                 return(0);
2403             }
2404         }
2405         else if ( ASSETCHAINS_CC == 0 && pindexPrev != 0 && ASSETCHAINS_STAKED == 0 && (ASSETCHAINS_SYMBOL[0] != 0 || IS_KOMODO_NOTARY == 0 || My_notaryid < 0) )
2406         {
2407             CValidationState state;
2408             //fprintf(stderr,"check validity\n");
2409             if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) // invokes CC checks
2410             {
2411                 throw std::runtime_error("CreateNewBlock(): TestBlockValidity failed");
2412             }
2413             //fprintf(stderr,"valid\n");
2414         }
2415     }
2416     //fprintf(stderr,"done new block\n");
2417
2418     // setup the header and buid the Merkle tree
2419     unsigned int extraNonce;
2420     IncrementExtraNonce(pblock, pindexPrev, extraNonce, true);
2421
2422     return pblocktemplate.release();
2423 }
2424
2425 CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& _scriptPubKeyIn, bool isStake)
2426 {
2427     std::vector<CTxOut> minerOutputs = _scriptPubKeyIn.size() ? std::vector<CTxOut>({CTxOut(1, _scriptPubKeyIn)}) : std::vector<CTxOut>();
2428     return CreateNewBlock(chainparams, minerOutputs, isStake);
2429 }
2430
2431 //////////////////////////////////////////////////////////////////////////////
2432 //
2433 // Internal miner
2434 //
2435
2436 #ifdef ENABLE_MINING
2437
2438 class MinerAddressScript : public CReserveScript
2439 {
2440     // CReserveScript requires implementing this function, so that if an
2441     // internal (not-visible) wallet address is used, the wallet can mark it as
2442     // important when a block is mined (so it then appears to the user).
2443     // If -mineraddress is set, the user already knows about and is managing the
2444     // address, so we don't need to do anything here.
2445     void KeepScript() {}
2446 };
2447
2448 void GetScriptForMinerAddress(boost::shared_ptr<CReserveScript> &script)
2449 {
2450     CTxDestination addr = DecodeDestination(GetArg("-mineraddress", ""));
2451     if (!IsValidDestination(addr)) {
2452         return;
2453     }
2454
2455     boost::shared_ptr<MinerAddressScript> mAddr(new MinerAddressScript());
2456     script = mAddr;
2457     script->reserveScript = GetScriptForDestination(addr);
2458 }
2459
2460 #ifdef ENABLE_WALLET
2461 //////////////////////////////////////////////////////////////////////////////
2462 //
2463 // Internal miner
2464 //
2465
2466 CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, bool isStake)
2467 {
2468     CPubKey pubkey; 
2469     CScript scriptPubKey; 
2470     uint8_t *ptr; 
2471     int32_t i;
2472     boost::shared_ptr<CReserveScript> coinbaseScript;
2473  
2474     if ( nHeight == 1 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 )
2475     {
2476         scriptPubKey = CScript() << ParseHex(ASSETCHAINS_OVERRIDE_PUBKEY) << OP_CHECKSIG;
2477     }
2478     else if ( USE_EXTERNAL_PUBKEY != 0 )
2479     {
2480         //fprintf(stderr,"use notary pubkey\n");
2481         scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG;
2482     }
2483     else if (GetArg("-mineraddress", "").empty() || !(GetScriptForMinerAddress(coinbaseScript), (scriptPubKey = coinbaseScript->reserveScript).size()))
2484     {
2485         if (!isStake)
2486         {
2487             if (!reservekey.GetReservedKey(pubkey))
2488             {
2489                 return NULL;
2490             }
2491             scriptPubKey = GetScriptForDestination(pubkey);
2492         }
2493     }
2494     return CreateNewBlock(Params(), scriptPubKey, isStake);
2495 }
2496
2497 void komodo_broadcast(const CBlock *pblock,int32_t limit)
2498 {
2499     int32_t n = 1;
2500     //fprintf(stderr,"broadcast new block t.%u\n",(uint32_t)time(NULL));
2501     {
2502         LOCK(cs_vNodes);
2503         BOOST_FOREACH(CNode* pnode, vNodes)
2504         {
2505             if ( pnode->hSocket == INVALID_SOCKET )
2506                 continue;
2507             if ( (rand() % n) == 0 )
2508             {
2509                 pnode->PushMessage("block", *pblock);
2510                 if ( n++ > limit )
2511                     break;
2512             }
2513         }
2514     }
2515     //fprintf(stderr,"finished broadcast new block t.%u\n",(uint32_t)time(NULL));
2516 }
2517
2518 static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
2519 #else
2520 static bool ProcessBlockFound(CBlock* pblock)
2521 #endif // ENABLE_WALLET
2522 {
2523     int32_t height = chainActive.LastTip()->GetHeight()+1;
2524     //LogPrintf("%s\n", pblock->ToString());
2525     LogPrintf("generated %s height.%d\n", FormatMoney(pblock->vtx[0].vout[0].nValue), height);
2526
2527     // Found a solution
2528     {
2529         if (pblock->hashPrevBlock != chainActive.LastTip()->GetBlockHash())
2530         {
2531             uint256 hash; int32_t i;
2532             hash = pblock->hashPrevBlock;
2533             for (i=31; i>=0; i--)
2534                 fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
2535             fprintf(stderr," <- prev (stale)\n");
2536             hash = chainActive.LastTip()->GetBlockHash();
2537             for (i=31; i>=0; i--)
2538                 fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
2539             fprintf(stderr," <- chainTip (stale)\n");
2540             
2541             return error("VerusMiner: generated block is stale");
2542         }
2543     }
2544     
2545 #ifdef ENABLE_WALLET
2546     // Remove key from key pool
2547     if ( IS_KOMODO_NOTARY == 0 )
2548     {
2549         if (GetArg("-mineraddress", "").empty()) {
2550             // Remove key from key pool
2551             reservekey.KeepKey();
2552         }
2553     }
2554     // Track how many getdata requests this block gets
2555     //if ( 0 )
2556     {
2557         //fprintf(stderr,"lock cs_wallet\n");
2558         LOCK(wallet.cs_wallet);
2559         wallet.mapRequestCount[pblock->GetHash()] = 0;
2560     }
2561 #endif
2562     //fprintf(stderr,"process new block\n");
2563
2564     // Process this block (almost) the same as if we had received it from another node
2565     CValidationState state;
2566     if (!ProcessNewBlock(1, chainActive.LastTip()->GetHeight()+1, state, Params(), NULL, pblock, true, NULL))
2567         return error("VerusMiner: ProcessNewBlock, block not accepted");
2568     
2569     TrackMinedBlock(pblock->GetHash());
2570     komodo_broadcast(pblock,16);
2571     return true;
2572 }
2573
2574 int32_t komodo_baseid(char *origbase);
2575 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,uint32_t *blocktimes,int32_t *nonzpkeysp,int32_t height);
2576 arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
2577 int32_t FOUND_BLOCK,KOMODO_MAYBEMINED;
2578 extern int32_t KOMODO_LASTMINED,KOMODO_INSYNC;
2579 int32_t roundrobin_delay;
2580 arith_uint256 HASHTarget,HASHTarget_POW;
2581 int32_t komodo_longestchain();
2582
2583 // wait for peers to connect
2584 void waitForPeers(const CChainParams &chainparams)
2585 {
2586     if (chainparams.MiningRequiresPeers())
2587     {
2588         bool fvNodesEmpty;
2589         {
2590             boost::this_thread::interruption_point();
2591             LOCK(cs_vNodes);
2592             fvNodesEmpty = vNodes.empty();
2593         }
2594         int longestchain = komodo_longestchain();
2595         int lastlongest = 0;
2596         if (fvNodesEmpty || IsNotInSync() || (longestchain != 0 && longestchain > chainActive.LastTip()->GetHeight()))
2597         {
2598             int loops = 0, blockDiff = 0, newDiff = 0;
2599             
2600             do {
2601                 if (fvNodesEmpty)
2602                 {
2603                     MilliSleep(1000 + rand() % 4000);
2604                     boost::this_thread::interruption_point();
2605                     LOCK(cs_vNodes);
2606                     fvNodesEmpty = vNodes.empty();
2607                     loops = 0;
2608                     blockDiff = 0;
2609                     lastlongest = 0;
2610                 }
2611                 else if ((newDiff = IsNotInSync()) > 0)
2612                 {
2613                     if (blockDiff != newDiff)
2614                     {
2615                         blockDiff = newDiff;
2616                     }
2617                     else
2618                     {
2619                         if (++loops <= 5)
2620                         {
2621                             MilliSleep(1000);
2622                         }
2623                         else break;
2624                     }
2625                     lastlongest = 0;
2626                 }
2627                 else if (!fvNodesEmpty && !IsNotInSync() && longestchain > chainActive.LastTip()->GetHeight())
2628                 {
2629                     // the only thing may be that we are seeing a long chain that we'll never get
2630                     // don't wait forever
2631                     if (lastlongest == 0)
2632                     {
2633                         MilliSleep(3000);
2634                         lastlongest = longestchain;
2635                     }
2636                 }
2637             } while (fvNodesEmpty || IsNotInSync());
2638             MilliSleep(500 + rand() % 1000);
2639         }
2640     }
2641 }
2642
2643 #ifdef ENABLE_WALLET
2644 CBlockIndex *get_chainactive(int32_t height)
2645 {
2646     if ( chainActive.LastTip() != 0 )
2647     {
2648         if ( height <= chainActive.LastTip()->GetHeight() )
2649         {
2650             LOCK(cs_main);
2651             return(chainActive[height]);
2652         }
2653         // else fprintf(stderr,"get_chainactive height %d > active.%d\n",height,chainActive.Tip()->GetHeight());
2654     }
2655     //fprintf(stderr,"get_chainactive null chainActive.Tip() height %d\n",height);
2656     return(0);
2657 }
2658
2659 /*
2660  * A separate thread to stake, while the miner threads mine.
2661  */
2662 void static VerusStaker(CWallet *pwallet)
2663 {
2664     LogPrintf("Verus staker thread started\n");
2665     RenameThread("verus-staker");
2666
2667     const CChainParams& chainparams = Params();
2668     auto consensusParams = chainparams.GetConsensus();
2669     bool isNotaryConnected = ConnectedChains.CheckVerusPBaaSAvailable();
2670
2671     // Each thread has its own key
2672     CReserveKey reservekey(pwallet);
2673
2674     // Each thread has its own counter
2675     unsigned int nExtraNonce = 0;
2676
2677     uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
2678
2679     while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->GetHeight() != 235300 &&
2680     {
2681         sleep(1);
2682         if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
2683             break;
2684     }
2685
2686     // try a nice clean peer connection to start
2687     CBlockIndex *pindexPrev, *pindexCur;
2688     do {
2689         pindexPrev = chainActive.LastTip();
2690         MilliSleep(5000 + rand() % 5000);
2691         waitForPeers(chainparams);
2692         pindexCur = chainActive.LastTip();
2693     } while (pindexPrev != pindexCur);
2694
2695     try {
2696         static int32_t lastStakingHeight = 0;
2697
2698         while (true)
2699         {
2700             waitForPeers(chainparams);
2701             CBlockIndex* pindexPrev = chainActive.LastTip();
2702
2703             // Create new block
2704             unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
2705
2706             if ( Mining_height != pindexPrev->GetHeight()+1 )
2707             {
2708                 Mining_height = pindexPrev->GetHeight()+1;
2709                 Mining_start = (uint32_t)time(NULL);
2710             }
2711
2712             // Check for stop or if block needs to be rebuilt
2713             boost::this_thread::interruption_point();
2714
2715             // try to stake a block
2716             CBlockTemplate *ptr = NULL;
2717
2718             // get height locally for consistent reporting
2719             int32_t newHeight = Mining_height;
2720
2721             if (newHeight > VERUS_MIN_STAKEAGE)
2722                 ptr = CreateNewBlockWithKey(reservekey, newHeight, true);
2723
2724             // TODO - putting this output here tends to help mitigate announcing a staking height earlier than
2725             // announcing the last block win when we start staking before a block's acceptance has been
2726             // acknowledged by the mining thread - a better solution may be to put the output on the submission
2727             // thread.
2728             if ( ptr == 0 && newHeight != lastStakingHeight )
2729             {
2730                 printf("Staking height %d for %s\n", newHeight, ASSETCHAINS_SYMBOL);
2731             }
2732             lastStakingHeight = newHeight;
2733
2734             if ( ptr == 0 )
2735             {
2736                 if (newHeight == 1 && (isNotaryConnected = ConnectedChains.IsNotaryAvailable()))
2737                 {
2738                     static int outputCounter;
2739                     if (outputCounter++ % 60 == 0)
2740                     {
2741                         printf("%s: waiting for confirmation of launch at or after block %u on %s before mining block 1\n", __func__, 
2742                                                                                         (uint32_t)ConnectedChains.ThisChain().startBlock, 
2743                                                                                         ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
2744                         sleep(1);
2745                     }
2746                 }
2747                 // wait to try another staking block until after the tip moves again
2748                 while ( chainActive.LastTip() == pindexPrev )
2749                     MilliSleep(250);
2750                 if (newHeight == 1)
2751                 {
2752                     sleep(10);
2753                 }
2754                 continue;
2755             }
2756
2757             unique_ptr<CBlockTemplate> pblocktemplate(ptr);
2758             if (!pblocktemplate.get())
2759             {
2760                 if (GetArg("-mineraddress", "").empty()) {
2761                     LogPrintf("Error in %s staker: Keypool ran out, please call keypoolrefill before restarting the mining thread\n",
2762                               ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2763                 } else {
2764                     // Should never reach here, because -mineraddress validity is checked in init.cpp
2765                     LogPrintf("Error in %s staker: Invalid %s -mineraddress\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], ASSETCHAINS_SYMBOL);
2766                 }
2767                 return;
2768             }
2769
2770             CBlock *pblock = &pblocktemplate->block;
2771             LogPrintf("Staking with %u transactions in block (%u bytes)\n", pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
2772             //
2773             // Search
2774             //
2775             int64_t nStart = GetTime();
2776
2777             if (vNodes.empty() && chainparams.MiningRequiresPeers())
2778             {
2779                 if ( Mining_height > ASSETCHAINS_MINHEIGHT )
2780                 {
2781                     fprintf(stderr,"no nodes, attempting reconnect\n");
2782                     continue;
2783                 }
2784             }
2785
2786             if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
2787             {
2788                 fprintf(stderr,"timeout, retrying\n");
2789                 continue;
2790             }
2791
2792             if ( pindexPrev != chainActive.LastTip() )
2793             {
2794                 printf("Block %d added to chain\n", chainActive.LastTip()->GetHeight());
2795                 MilliSleep(250);
2796                 continue;
2797             }
2798
2799             int32_t unlockTime = komodo_block_unlocktime(Mining_height);
2800             int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
2801
2802             uint256 hashTarget = ArithToUint256(arith_uint256().SetCompact(pblock->nBits));
2803
2804             pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
2805
2806             UpdateTime(pblock, consensusParams, pindexPrev);
2807
2808             if (ProcessBlockFound(pblock, *pwallet, reservekey))
2809             {
2810                 LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2811                 LogPrintf("Staked block found  \n  hash: %s  \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex());
2812                 printf("Found block %d \n", newHeight);
2813                 printf("staking reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
2814                 arith_uint256 post;
2815                 post.SetCompact(pblock->GetVerusPOSTarget());
2816
2817                 CTransaction &sTx = pblock->vtx[pblock->vtx.size()-1];
2818                 printf("POS hash: %s  \ntarget:   %s\n", 
2819                     CTransaction::_GetVerusPOSHash(&(pblock->nNonce), 
2820                                                      sTx.vin[0].prevout.hash, 
2821                                                      sTx.vin[0].prevout.n, 
2822                                                      newHeight, 
2823                                                      chainActive.GetVerusEntropyHash(newHeight), 
2824                                                      sTx.vout[0].nValue).GetHex().c_str(), 
2825                                                      ArithToUint256(post).GetHex().c_str());
2826                 if (unlockTime > newHeight && subsidy >= ASSETCHAINS_TIMELOCKGTE)
2827                     printf("- timelocked until block %i\n", unlockTime);
2828                 else
2829                     printf("\n");
2830             }
2831             else
2832             {
2833                 LogPrintf("Found block rejected at staking height: %d\n", Mining_height);
2834                 printf("Found block rejected at staking height: %d\n", Mining_height);
2835             }
2836
2837             // Check for stop or if block needs to be rebuilt
2838             boost::this_thread::interruption_point();
2839
2840             sleep(3);
2841
2842             // In regression test mode, stop mining after a block is found.
2843             if (chainparams.MineBlocksOnDemand()) {
2844                 throw boost::thread_interrupted();
2845             }
2846         }
2847     }
2848     catch (const boost::thread_interrupted&)
2849     {
2850         LogPrintf("VerusStaker terminated\n");
2851         throw;
2852     }
2853     catch (const std::runtime_error &e)
2854     {
2855         LogPrintf("VerusStaker runtime error: %s\n", e.what());
2856         return;
2857     }
2858 }
2859
2860 typedef bool (*minefunction)(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
2861 bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
2862 bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
2863
2864 void static BitcoinMiner_noeq(CWallet *pwallet)
2865 #else
2866 void static BitcoinMiner_noeq()
2867 #endif
2868 {
2869     LogPrintf("%s miner started\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2870     RenameThread("verushash-miner");
2871
2872 #ifdef ENABLE_WALLET
2873     // Each thread has its own key
2874     CReserveKey reservekey(pwallet);
2875 #endif
2876
2877     miningTimer.clear();
2878
2879     const CChainParams& chainparams = Params();
2880     // Each thread has its own counter
2881     unsigned int nExtraNonce = 0;
2882
2883     uint8_t *script; uint64_t total,checktoshis; int32_t i,j;
2884
2885     while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) //chainActive.Tip()->GetHeight() != 235300 &&
2886     {
2887         sleep(1);
2888         if ( komodo_baseid(ASSETCHAINS_SYMBOL) < 0 )
2889             break;
2890     }
2891
2892     SetThreadPriority(THREAD_PRIORITY_LOWEST);
2893
2894     // try a nice clean peer connection to start
2895     CBlockIndex *pindexPrev, *pindexCur;
2896     do {
2897         pindexPrev = chainActive.LastTip();
2898         MilliSleep(5000 + rand() % 5000);
2899         waitForPeers(chainparams);
2900         pindexCur = chainActive.LastTip();
2901     } while (pindexPrev != pindexCur);
2902
2903     // make sure that we have checked for PBaaS availability
2904     ConnectedChains.CheckVerusPBaaSAvailable();
2905
2906     // this will not stop printing more than once in all cases, but it will allow us to print in all cases
2907     // and print duplicates rarely without having to synchronize
2908     static CBlockIndex *lastChainTipPrinted;
2909     static int32_t lastMiningHeight = 0;
2910
2911     miningTimer.start();
2912
2913     try {
2914         printf("Mining %s with %s\n", ASSETCHAINS_SYMBOL, ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2915
2916         while (true)
2917         {
2918             miningTimer.stop();
2919             waitForPeers(chainparams);
2920
2921             pindexPrev = chainActive.LastTip();
2922
2923             // prevent forking on startup before the diff algorithm kicks in,
2924             // but only for a startup Verus test chain. PBaaS chains have the difficulty inherited from
2925             // their parent
2926             if (chainparams.MiningRequiresPeers() && ((IsVerusActive() && pindexPrev->GetHeight() < 50) || pindexPrev != chainActive.LastTip()))
2927             {
2928                 do {
2929                     pindexPrev = chainActive.LastTip();
2930                     MilliSleep(2000 + rand() % 2000);
2931                 } while (pindexPrev != chainActive.LastTip());
2932             }
2933
2934             // Create new block
2935             unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
2936             if ( Mining_height != pindexPrev->GetHeight()+1 )
2937             {
2938                 Mining_height = pindexPrev->GetHeight()+1;
2939                 if (lastMiningHeight != Mining_height)
2940                 {
2941                     lastMiningHeight = Mining_height;
2942                     printf("Mining %s at height %d\n", ASSETCHAINS_SYMBOL, Mining_height);
2943                 }
2944                 Mining_start = (uint32_t)time(NULL);
2945             }
2946
2947             miningTimer.start();
2948
2949 #ifdef ENABLE_WALLET
2950             CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey, Mining_height);
2951 #else
2952             CBlockTemplate *ptr = CreateNewBlockWithKey();
2953 #endif
2954             if ( ptr == 0 )
2955             {
2956                 static uint32_t counter;
2957                 if ( counter++ % 40 == 0 )
2958                 {
2959                     if (!IsVerusActive() &&
2960                         ConnectedChains.IsNotaryAvailable() &&
2961                         !ConnectedChains.readyToStart)
2962                     {
2963                         fprintf(stderr,"waiting for confirmation of launch at or after block %u on %s chain to start\n", (uint32_t)ConnectedChains.ThisChain().startBlock,
2964                                                                                         ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
2965                     }
2966                     else
2967                     {
2968                         fprintf(stderr,"Unable to create valid block... will continue to try\n");
2969                     }
2970                 }
2971                 MilliSleep(2000);
2972                 continue;
2973             }
2974
2975             unique_ptr<CBlockTemplate> pblocktemplate(ptr);
2976             if (!pblocktemplate.get())
2977             {
2978                 if (GetArg("-mineraddress", "").empty()) {
2979                     LogPrintf("Error in %s miner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n",
2980                               ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
2981                 } else {
2982                     // Should never reach here, because -mineraddress validity is checked in init.cpp
2983                     LogPrintf("Error in %s miner: Invalid %s -mineraddress\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], ASSETCHAINS_SYMBOL);
2984                 }
2985                 miningTimer.stop();
2986                 miningTimer.clear();
2987                 return;
2988             }
2989             CBlock *pblock = &pblocktemplate->block;
2990
2991             uint32_t savebits;
2992             bool mergeMining = false;
2993             savebits = pblock->nBits;
2994
2995             uint32_t solutionVersion = CConstVerusSolutionVector::Version(pblock->nSolution);
2996             if (pblock->nVersion != CBlockHeader::VERUS_V2)
2997             {
2998                 // must not be in sync
2999                 printf("Mining on incorrect block version.\n");
3000                 sleep(2);
3001                 continue;
3002             }
3003             bool verusSolutionPBaaS = solutionVersion >= CActivationHeight::ACTIVATE_PBAAS;
3004
3005             // v2 hash writer with adjustments for the current height
3006             CVerusHashV2bWriter ss2 = CVerusHashV2bWriter(SER_GETHASH, PROTOCOL_VERSION, solutionVersion);
3007
3008             if ( ASSETCHAINS_SYMBOL[0] != 0 )
3009             {
3010                 if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
3011                 {
3012                     if ( pblock->vtx.size() == 1 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT )
3013                     {
3014                         static uint32_t counter;
3015                         if ( counter++ < 10 )
3016                             fprintf(stderr,"skip generating %s on-demand block, no tx avail\n",ASSETCHAINS_SYMBOL);
3017                         sleep(10);
3018                         continue;
3019                     } else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
3020                 }
3021             }
3022
3023             // set our easiest target, if V3+, no need to rebuild the merkle tree
3024             IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, verusSolutionPBaaS ? false : true, &savebits);
3025
3026             // update PBaaS header
3027             if (verusSolutionPBaaS)
3028             {
3029                 if (!IsVerusActive() && ConnectedChains.IsVerusPBaaSAvailable())
3030                 {
3031
3032                     UniValue params(UniValue::VARR);
3033                     UniValue error(UniValue::VARR);
3034                     params.push_back(EncodeHexBlk(*pblock));
3035                     params.push_back(ASSETCHAINS_SYMBOL);
3036                     params.push_back(ASSETCHAINS_RPCHOST);
3037                     params.push_back(ASSETCHAINS_RPCPORT);
3038                     params.push_back(ASSETCHAINS_RPCCREDENTIALS);
3039                     try
3040                     {
3041                         ConnectedChains.lastSubmissionFailed = false;
3042                         params = RPCCallRoot("addmergedblock", params);
3043                         params = find_value(params, "result");
3044                         error = find_value(params, "error");
3045                     } catch (std::exception e)
3046                     {
3047                         printf("Failed to connect to %s chain\n", ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
3048                         params = UniValue(e.what());
3049                     }
3050                     if (mergeMining = (params.isNull() && error.isNull()))
3051                     {
3052                         printf("Merge mining %s with %s as the hashing chain\n", ASSETCHAINS_SYMBOL, ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
3053                         LogPrintf("Merge mining with %s as the hashing chain\n", ConnectedChains.FirstNotaryChain().chainDefinition.name.c_str());
3054                     }
3055                 }
3056             }
3057
3058             LogPrintf("Running %s miner with %u transactions in block (%u bytes)\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO],
3059                        pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
3060             //
3061             // Search
3062             //
3063             int64_t nStart = GetTime();
3064
3065             arith_uint256 hashTarget = arith_uint256().SetCompact(savebits);
3066             uint256 uintTarget = ArithToUint256(hashTarget);
3067             arith_uint256 ourTarget;
3068             ourTarget.SetCompact(pblock->nBits);
3069
3070             Mining_start = 0;
3071
3072             if ( pindexPrev != chainActive.LastTip() )
3073             {
3074                 if (lastChainTipPrinted != chainActive.LastTip())
3075                 {
3076                     lastChainTipPrinted = chainActive.LastTip();
3077                     printf("Block %d added to chain\n", lastChainTipPrinted->GetHeight());
3078                 }
3079                 MilliSleep(100);
3080                 continue;
3081             }
3082
3083             uint64_t count;
3084             uint64_t hashesToGo = 0;
3085             uint64_t totalDone = 0;
3086
3087             int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
3088             count = ((ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1) / ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
3089             CVerusHashV2 *vh2 = &ss2.GetState();
3090             u128 *hashKey;
3091             verusclhasher &vclh = vh2->vclh;
3092             minefunction mine_verus;
3093             mine_verus = IsCPUVerusOptimized() ? &mine_verus_v2 : &mine_verus_v2_port;
3094
3095             while (true)
3096             {
3097                 uint256 hashResult = uint256();
3098
3099                 unsigned char *curBuf;
3100
3101                 if (mergeMining)
3102                 {
3103                     // loop for a few minutes before refreshing the block
3104                     while (true)
3105                     {
3106                         uint256 ourMerkle = pblock->hashMerkleRoot;
3107                         if ( pindexPrev != chainActive.LastTip() )
3108                         {
3109                             if (lastChainTipPrinted != chainActive.LastTip())
3110                             {
3111                                 lastChainTipPrinted = chainActive.LastTip();
3112                                 printf("Block %d added to chain\n\n", lastChainTipPrinted->GetHeight());
3113                                 arith_uint256 target;
3114                                 target.SetCompact(lastChainTipPrinted->nBits);
3115                                 if (ourMerkle == lastChainTipPrinted->hashMerkleRoot)
3116                                 {
3117                                     LogPrintf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", lastChainTipPrinted->GetBlockHash().GetHex().c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3118                                     printf("Found block %d \n", lastChainTipPrinted->GetHeight());
3119                                     printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
3120                                     printf("  hash: %s\ntarget: %s\n", lastChainTipPrinted->GetBlockHash().GetHex().c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3121                                 }
3122                             }
3123                             break;
3124                         }
3125
3126                         // if PBaaS is no longer available, we can't count on merge mining
3127                         if (!ConnectedChains.IsVerusPBaaSAvailable())
3128                         {
3129                             break;
3130                         }
3131
3132                         if (vNodes.empty() && chainparams.MiningRequiresPeers())
3133                         {
3134                             if ( Mining_height > ASSETCHAINS_MINHEIGHT )
3135                             {
3136                                 fprintf(stderr,"no nodes, attempting reconnect\n");
3137                                 break;
3138                             }
3139                         }
3140
3141                         // update every few minutes, regardless
3142                         int64_t elapsed = GetTime() - nStart;
3143
3144                         if ((mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && elapsed > 60) || elapsed > 60 || ConnectedChains.lastSubmissionFailed)
3145                         {
3146                             break;
3147                         }
3148
3149                         boost::this_thread::interruption_point();
3150                         MilliSleep(500);
3151                     }
3152                     break;
3153                 }
3154                 else
3155                 {
3156                     // check NONCEMASK at a time
3157                     for (uint64_t i = 0; i < count; i++)
3158                     {
3159                         // 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
3160                         // merge mined block, but not our own
3161                         bool blockFound;
3162                         arith_uint256 arithHash;
3163                         totalDone = 0;
3164                         do
3165                         {
3166                             // pickup/remove any new/deleted headers
3167                             if (ConnectedChains.dirty || (pblock->NumPBaaSHeaders() < ConnectedChains.mergeMinedChains.size() + 1))
3168                             {
3169                                 IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, verusSolutionPBaaS ? false : true, &savebits);
3170
3171                                 hashTarget.SetCompact(savebits);
3172                                 uintTarget = ArithToUint256(hashTarget);
3173                             }
3174
3175                             // hashesToGo gets updated with actual number run for metrics
3176                             hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
3177                             uint64_t start = i * hashesToGo + totalDone;
3178                             hashesToGo -= totalDone;
3179
3180                             if (verusSolutionPBaaS)
3181                             {
3182                                 // mine on canonical header for merge mining
3183                                 CPBaaSPreHeader savedHeader(*pblock);
3184
3185                                 pblock->ClearNonCanonicalData();
3186                                 blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
3187                                 savedHeader.SetBlockData(*pblock);
3188                             }
3189                             else
3190                             {
3191                                 blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
3192                             }
3193
3194                             arithHash = UintToArith256(hashResult);
3195                             totalDone += hashesToGo + 1;
3196                             if (blockFound && IsVerusActive())
3197                             {
3198                                 ConnectedChains.QueueNewBlockHeader(*pblock);
3199                                 if (arithHash > ourTarget)
3200                                 {
3201                                     // all blocks qualified with this hash will be submitted
3202                                     // until we redo the block, we might as well not try again with anything over this hash
3203                                     hashTarget = arithHash;
3204                                     uintTarget = ArithToUint256(hashTarget);
3205                                 }
3206                             }
3207                         } while (blockFound && arithHash > ourTarget);
3208
3209                         if (!blockFound || arithHash > ourTarget)
3210                         {
3211                             // Check for stop or if block needs to be rebuilt
3212                             boost::this_thread::interruption_point();
3213                             if ( pindexPrev != chainActive.LastTip() )
3214                             {
3215                                 if (lastChainTipPrinted != chainActive.LastTip())
3216                                 {
3217                                     lastChainTipPrinted = chainActive.LastTip();
3218                                     printf("Block %d added to chain\n", lastChainTipPrinted->GetHeight());
3219                                 }
3220                                 break;
3221                             }
3222                             else if ((i + 1) < count)
3223                             {
3224                                 // if we'll not drop through, update hashcount
3225                                 {
3226                                     miningTimer += totalDone;
3227                                     totalDone = 0;
3228                                 }
3229                             }
3230                         }
3231                         else
3232                         {
3233                             // Check for stop or if block needs to be rebuilt
3234                             boost::this_thread::interruption_point();
3235
3236                             if (pblock->nSolution.size() != 1344)
3237                             {
3238                                 LogPrintf("ERROR: Block solution is not 1344 bytes as it should be");
3239                                 break;
3240                             }
3241
3242                             SetThreadPriority(THREAD_PRIORITY_NORMAL);
3243
3244                             int32_t unlockTime = komodo_block_unlocktime(Mining_height);
3245
3246 #ifdef VERUSHASHDEBUG
3247                             std::string validateStr = hashResult.GetHex();
3248                             std::string hashStr = pblock->GetHash().GetHex();
3249                             uint256 *bhalf1 = (uint256 *)vh2->CurBuffer();
3250                             uint256 *bhalf2 = bhalf1 + 1;
3251 #else
3252                             std::string hashStr = hashResult.GetHex();
3253 #endif
3254
3255                             LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
3256                             LogPrintf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", hashStr, ArithToUint256(ourTarget).GetHex());
3257                             printf("Found block %d \n", Mining_height );
3258                             printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
3259 #ifdef VERUSHASHDEBUG
3260                             printf("  hash: %s\n   val: %s  \ntarget: %s\n\n", hashStr.c_str(), validateStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3261                             printf("intermediate %lx\n", intermediate);
3262                             printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
3263                             bhalf1 = (uint256 *)verusclhasher_key.get();
3264                             bhalf2 = bhalf1 + ((vh2->vclh.keyMask + 1) >> 5);
3265                             printf("   Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
3266 #else
3267                             printf("  hash: %s\ntarget: %s", hashStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
3268 #endif
3269                             if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
3270                                 printf(" - timelocked until block %i\n", unlockTime);
3271                             else
3272                                 printf("\n");
3273 #ifdef ENABLE_WALLET
3274                             ProcessBlockFound(pblock, *pwallet, reservekey);
3275 #else
3276                             ProcessBlockFound(pblock);
3277 #endif
3278                             SetThreadPriority(THREAD_PRIORITY_LOWEST);
3279                             break;
3280                         }
3281                     }
3282
3283                     {
3284                         miningTimer += totalDone;
3285                     }
3286                 }
3287                 
3288
3289                 // Check for stop or if block needs to be rebuilt
3290                 boost::this_thread::interruption_point();
3291
3292                 if (vNodes.empty() && chainparams.MiningRequiresPeers())
3293                 {
3294                     if ( Mining_height > ASSETCHAINS_MINHEIGHT )
3295                     {
3296                         fprintf(stderr,"no nodes, attempting reconnect\n");
3297                         break;
3298                     }
3299                 }
3300
3301                 if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
3302                 {
3303                     fprintf(stderr,"timeout, retrying\n");
3304                     break;
3305                 }
3306
3307                 if ( pindexPrev != chainActive.LastTip() )
3308                 {
3309                     if (lastChainTipPrinted != chainActive.LastTip())
3310                     {
3311                         lastChainTipPrinted = chainActive.LastTip();
3312                         printf("Block %d added to chain\n\n", lastChainTipPrinted->GetHeight());
3313                     }
3314                     break;
3315                 }
3316
3317                 // totalDone now has the number of hashes actually done since starting on one nonce mask worth
3318                 uint64_t hashesPerNonceMask = ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3;
3319                 if (!(totalDone < hashesPerNonceMask))
3320                 {
3321 #ifdef _WIN32
3322                     printf("%llu mega hashes complete - working\n", (hashesPerNonceMask + 1) / 1048576);
3323 #else
3324                     printf("%lu mega hashes complete - working\n", (hashesPerNonceMask + 1) / 1048576);
3325 #endif
3326                 }
3327                 break;
3328
3329             }
3330         }
3331     }
3332     catch (const boost::thread_interrupted&)
3333     {
3334         miningTimer.stop();
3335         miningTimer.clear();
3336         LogPrintf("%s miner terminated\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
3337         throw;
3338     }
3339     catch (const std::runtime_error &e)
3340     {
3341         miningTimer.stop();
3342         miningTimer.clear();
3343         LogPrintf("%s miner runtime error: %s\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO], e.what());
3344         return;
3345     }
3346     miningTimer.stop();
3347     miningTimer.clear();
3348 }
3349
3350 #ifdef ENABLE_WALLET
3351     void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
3352 #else
3353     void GenerateBitcoins(bool fGenerate, int nThreads)
3354 #endif
3355     {
3356         static CCriticalSection cs_startmining;
3357
3358         LOCK(cs_startmining);
3359         if (!AreParamsInitialized())
3360         {
3361             return;
3362         }
3363
3364         VERUS_MINTBLOCKS = (VERUS_MINTBLOCKS && ASSETCHAINS_LWMAPOS != 0);
3365
3366         if (fGenerate == true || VERUS_MINTBLOCKS)
3367         {
3368             mapArgs["-gen"] = "1";
3369
3370             if (VERUS_DEFAULT_ZADDR.size() > 0)
3371             {
3372                 if (defaultSaplingDest == boost::none)
3373                 {
3374                     LogPrintf("ERROR: -defaultzaddr parameter is invalid Sapling payment address\n");
3375                     fprintf(stderr, "-defaultzaddr parameter is invalid Sapling payment address\n");
3376                 }
3377                 else
3378                 {
3379                     LogPrintf("StakeGuard searching for double stakes on %s\n", VERUS_DEFAULT_ZADDR.c_str());
3380                     fprintf(stderr, "StakeGuard searching for double stakes on %s\n", VERUS_DEFAULT_ZADDR.c_str());
3381                 }
3382             }
3383         }
3384
3385         static boost::thread_group* minerThreads = NULL;
3386
3387         if (nThreads < 0)
3388             nThreads = GetNumCores();
3389
3390         if (minerThreads != NULL)
3391         {
3392             minerThreads->interrupt_all();
3393             minerThreads->join_all();
3394             delete minerThreads;
3395             minerThreads = NULL;
3396         }
3397
3398         //fprintf(stderr,"nThreads.%d fGenerate.%d\n",(int32_t)nThreads,fGenerate);
3399         if ( nThreads == 0 && ASSETCHAINS_STAKED )
3400             nThreads = 1;
3401
3402         if (!fGenerate)
3403             return;
3404
3405         minerThreads = new boost::thread_group();
3406
3407         // add the PBaaS thread when mining or staking
3408         minerThreads->create_thread(boost::bind(&CConnectedChains::SubmissionThreadStub));
3409
3410 #ifdef ENABLE_WALLET
3411         if (VERUS_MINTBLOCKS && pwallet != NULL)
3412         {
3413             minerThreads->create_thread(boost::bind(&VerusStaker, pwallet));
3414         }
3415 #endif
3416
3417         for (int i = 0; i < nThreads; i++) {
3418 #ifdef ENABLE_WALLET
3419             minerThreads->create_thread(boost::bind(&BitcoinMiner_noeq, pwallet));
3420 #else
3421             minerThreads->create_thread(&BitcoinMiner_noeq);
3422 #endif
3423         }
3424     }
3425     
3426 #endif // ENABLE_MINING
This page took 0.231848 seconds and 4 git commands to generate.