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