]> Git Repo - VerusCoin.git/blobdiff - src/miner.cpp
Ensure correct connectivity params
[VerusCoin.git] / src / miner.cpp
index b4d57ae6470efb37a6639da911e78d39efc3e216..d2c1fe7930aea085a22e8d7b528bbc49e8aaa259 100644 (file)
@@ -47,6 +47,9 @@
 #endif
 #include <mutex>
 
+#include "pbaas/pbaas.h"
+#include "pbaas/notarization.h"
+
 using namespace std;
 
 //////////////////////////////////////////////////////////////////////////////
@@ -124,6 +127,13 @@ extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGT
 extern const char *ASSETCHAINS_ALGORITHMS[];
 extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
+extern uint160 ASSETCHAINS_CHAINID;
+extern uint160 VERUS_CHAINID;
+extern std::string VERUS_CHAINNAME;
+extern int32_t PBAAS_STARTBLOCK, PBAAS_ENDBLOCK;
+extern string PBAAS_HOST, PBAAS_USERPASS, ASSETCHAINS_RPCHOST, ASSETCHAINS_RPCCREDENTIALS;;
+extern int32_t PBAAS_PORT;
+extern uint16_t ASSETCHAINS_RPCPORT;
 extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY;
 void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
 
@@ -338,6 +348,90 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
             }
         }
 
+        // if we are a PBaaS chain, first make sure we don't start prematurely, and if
+        // we should make an earned notarization, make it and set index to non-zero value
+        int32_t pbaasNotarizationTx = 0;
+        int64_t pbaasTransparentIn = 0;
+        int64_t pbaasTransparentOut = 0;
+        uint256 mmrRoot;
+        if (!IsVerusActive())
+        {
+            // if we don't have a connected root PBaaS chain, we can't properly check
+            // and notarize the start block, so we have to pass and wait
+            if (nHeight != 1 || (ConnectedChains.IsVerusPBaaSAvailable() && ConnectedChains.notaryChainHeight >= PBAAS_STARTBLOCK))
+            {
+                // if we have access to our parent daemon
+                // create a notarization, if we would qualify, and add it to the mempool and block
+                CMutableTransaction newNotarizationTx;
+                CTransaction prevTx, crossTx;
+                ChainMerkleMountainView mmv = chainActive.GetMMV();
+                mmrRoot = mmv.GetRoot();
+                if (CreateEarnedNotarization(newNotarizationTx, prevTx, crossTx, nHeight, mmrRoot))
+                {
+                    // we have a valid, earned notarization transaction. we still need to verify:
+                    // 1. it has matching input for its outputs, since it can be returned with less than enough, 
+                    // if there is not enough, take it as instant-spend from the coinbase. if there is too much,
+                    // increase the output on the main notarization thread.
+                    // instant-spend and notarization 
+                    // transaction threads on a PBaaS chain can only be used for notarization, and can never convert to 
+                    // available supply
+
+                    // Fetch previous transactions (inputs):
+                    for (const CTxIn& txin : newNotarizationTx.vin)
+                    {
+                        const uint256& prevHash = txin.prevout.hash;
+                        const CCoins *pcoins = view.AccessCoins(prevHash); // this is certainly allowed to fail
+                        pbaasTransparentIn += pcoins && (pcoins->vout.size() > txin.prevout.n) ? pcoins->vout[txin.prevout.n].nValue : 0;
+                    }
+
+                    for (auto txout : newNotarizationTx.vout)
+                    {
+                        pbaasTransparentOut += txout.nValue;
+                    }
+
+                    if (pbaasTransparentOut < pbaasTransparentIn)
+                    {
+                        // add excess to the notarization output
+                        int notarizeOut = -1;
+                        for (int outIdx = 0; outIdx < newNotarizationTx.vout.size(); outIdx++)
+                        {
+                            uint32_t ecode;
+                            if (newNotarizationTx.vout[outIdx].scriptPubKey.IsPayToCryptoCondition(&ecode))
+                            {
+                                if (ecode == EVAL_EARNEDNOTARIZATION)
+                                {
+                                    newNotarizationTx.vout[outIdx].nValue += pbaasTransparentIn - pbaasTransparentOut;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    
+                    if (pbaasTransparentOut > pbaasTransparentIn)
+                    {
+                        // add a non-fungible input to bind the notarization to the block, specific to block height, previous MMR
+                        // output will be added to coinbase with the same notarization output as well
+                        newNotarizationTx.vin.push_back(CTxIn(::GetHash(CPBaaSNotarization(newNotarizationTx)), 0));
+                    }
+
+                    pblock->vtx.push_back(CTransaction(newNotarizationTx));
+                    pblocktemplate->vTxFees.push_back(0);
+                    pblocktemplate->vTxSigOps.push_back(-1); // updated at end
+                    pbaasNotarizationTx = pblock->vtx.size() - 1;
+                }
+                else if (nHeight == 1)
+                {
+                    // failed to notarize at block 1
+                    return NULL;
+                }
+            }
+            else
+            {
+                // can't mine block 1 unless we have a connection to Verus and can notarize
+                return NULL;
+            }
+        }
+
         // now add transactions from the mem pool
         for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
              mi != mempool.mapTx.end(); ++mi)
@@ -674,13 +768,115 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
             //printf("autocreate commision vout\n");
         }
 
+        // add final notarization and instant spend fixups
+        if (pbaasNotarizationTx)
+        {
+            extern CWallet *pwalletMain;
+            LOCK(pwalletMain->cs_wallet);
+
+            CMutableTransaction mntx(pblock->vtx[pbaasNotarizationTx]);
+
+            // determine number of outputs
+            int numNotaryOutputs = mntx.vout.size() - (mntx.vout[mntx.vout.size() - 1].scriptPubKey.IsOpReturn() ? 1 : 0);
+
+            int64_t needed = pbaasTransparentOut - pbaasTransparentIn;
+            if (needed > PBAAS_MINNOTARIZATIONOUTPUT * numNotaryOutputs)
+            {
+                fprintf(stderr,"CreateNewBlock: too much output from earned notarization transaction\n");
+                return NULL;
+            }
+
+            int32_t pbaasCoinbaseInstantSpendOut;
+
+            // if we need an instant out to be a source of funds for the notarization transaction, make it here
+            if (needed > 0)
+            {
+                // the new instant spend out will go at the end and before any opret
+                pbaasCoinbaseInstantSpendOut = txNew.vout.size() - (txNew.vout[txNew.vout.size() - 1].scriptPubKey.IsOpReturn() ? 1 : 0);
+
+                auto coinbaseOutIt = txNew.vout.begin() + pbaasCoinbaseInstantSpendOut;
+
+                CCcontract_info CC;
+                CCcontract_info *cp;
+                vector<CTxDestination> vKeys;
+
+                // make the earned notarization output
+                cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
+                // send this to EVAL_EARNEDNOTARIZATION address as a destination, locked by the default pubkey
+                CPubKey pk(ParseHex(cp->CChexstr));
+
+                vKeys.push_back(CTxDestination(CKeyID(CCrossChainRPCData::GetConditionID(VERUS_CHAINID, EVAL_EARNEDNOTARIZATION))));
+
+                // output duplicate notarization as coinbase output for instant spend to notarization
+                // the output is 0 and will be used to match, not to spend, so it does not need to be considered as
+                // part of the total value of this coinbase
+                CPBaaSNotarization pbn(pblock->vtx[pbaasNotarizationTx]);
+                txNew.vout.insert(coinbaseOutIt, MakeCC1of1Vout(EVAL_EARNEDNOTARIZATION, 0, pk, vKeys, pbn));
+                pblock->vtx[0] = txNew;
+
+                // bind to the right output of the coinbase
+                mntx.vin[mntx.vin.size() - 1].prevout.n = pbaasCoinbaseInstantSpendOut;
+
+                // put notarization back in the block
+                pblock->vtx[pbaasNotarizationTx] = mntx;
+            }
+
+            CTransaction ntx(mntx);
+
+            for (int i = 0, endat = (needed > 0 ? ntx.vin.size() - 1 : ntx.vin.size()); i < endat; i++)
+            {
+                bool signSuccess;
+                SignatureData sigdata;
+                CAmount value;
+                const CScript *pScriptPubKey;
+
+                const CScript virtualCC;
+                CTxOut virtualCCOut;
+
+                if (needed > 0 && mmrRoot == ntx.vin[i].prevout.hash && nHeight == ntx.vin[i].prevout.n)
+                {
+                    CCcontract_info CC;
+                    CCcontract_info *cp;
+                    vector<CTxDestination> vKeys;
+
+                    // make the earned notarization output, but don't keep it
+                    // on validation, we can ensure that an accurate notarization was spent as
+                    cp = CCinit(&CC, EVAL_EARNEDNOTARIZATION);
+                    CPubKey pk(ParseHex(cp->CChexstr));
+                    vKeys.push_back(CTxDestination(CKeyID(CCrossChainRPCData::GetConditionID(VERUS_CHAINID, EVAL_EARNEDNOTARIZATION))));
+                    CPBaaSNotarization pbn(pblock->vtx[pbaasNotarizationTx]);
+                    virtualCCOut = MakeCC1of1Vout(EVAL_EARNEDNOTARIZATION, needed, pk, vKeys, pbn);
+
+                    pScriptPubKey = &virtualCCOut.scriptPubKey;
+                    value = virtualCCOut.nValue;
+                }
+                else
+                {
+                    const CCoins *coins = view.AccessCoins(ntx.vin[i].prevout.hash);
+                    pScriptPubKey = &coins->vout[ntx.vin[i].prevout.n].scriptPubKey;
+                    value = coins->vout[ntx.vin[i].prevout.n].nValue;
+                }
+
+                signSuccess = ProduceSignature(TransactionSignatureCreator(pwalletMain, &ntx, i, value, SIGHASH_ALL), *pScriptPubKey, sigdata, consensusBranchId);
+
+                if (!signSuccess)
+                {
+                    fprintf(stderr,"CreateNewBlock: failure to sign earned notarization\n");
+                    return NULL;
+                } else {
+                    UpdateTransaction(mntx, i, sigdata);
+                }
+            }
+            pblocktemplate->vTxSigOps[pbaasNotarizationTx] = GetLegacySigOpCount(mntx);
+        }
+
         pblock->vtx[0] = txNew;
         pblocktemplate->vTxFees[0] = -nFees;
 
         // if not Verus stake, setup nonce, otherwise, leave it alone
         if (!isStake || ASSETCHAINS_LWMAPOS == 0)
         {
-            // Randomise nonce
+            // Randomize nonce
             arith_uint256 nonce = UintToArith256(GetRandHash());
 
             // Clear the top 16 and bottom 16 or 24 bits (for local use as thread flags and counters)
@@ -701,6 +897,7 @@ CBlockTemplate* CreateNewBlock(const CScript& _scriptPubKeyIn, int32_t gpucount,
         }
 
         pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]);
+
         if ( ASSETCHAINS_SYMBOL[0] == 0 && IS_KOMODO_NOTARY != 0 && My_notaryid >= 0 )
         {
             uint32_t r;
@@ -899,7 +1096,7 @@ static bool ProcessBlockFound(CBlock* pblock)
                 fprintf(stderr,"%02x",((uint8_t *)&hash)[i]);
             fprintf(stderr," <- chainTip (stale)\n");
             
-            return error("KomodoMiner: generated block is stale");
+            return error("VerusMiner: generated block is stale");
         }
     }
     
@@ -925,7 +1122,7 @@ static bool ProcessBlockFound(CBlock* pblock)
     // Process this block the same as if we had received it from another node
     CValidationState state;
     if (!ProcessNewBlock(1,chainActive.LastTip()->GetHeight()+1,state, NULL, pblock, true, NULL))
-        return error("KomodoMiner: ProcessNewBlock, block not accepted");
+        return error("VerusMiner: ProcessNewBlock, block not accepted");
     
     TrackMinedBlock(pblock->GetHash());
     komodo_broadcast(pblock,16);
@@ -1087,7 +1284,7 @@ void static VerusStaker(CWallet *pwallet)
             {
                 // wait to try another staking block until after the tip moves again
                 while ( chainActive.LastTip() == pindexPrev )
-                    MilliSleep(100);
+                    MilliSleep(250);
                 continue;
             }
 
@@ -1115,6 +1312,19 @@ void static VerusStaker(CWallet *pwallet)
             unsigned int nExtraNonce = 0;
             IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
 
+            // update PBaaS header
+            if (CConstVerusSolutionVector::activationHeight.ActiveVersion(Mining_height) == CActivationHeight::SOLUTION_VERUSV3)
+            {
+                uint256 mmvRoot;
+                {
+                    LOCK(cs_main);
+                    // set the PBaaS header
+                    ChainMerkleMountainView mmv = chainActive.GetMMV();
+                    mmvRoot = mmv.GetRoot();
+                }
+                pblock->AddUpdatePBaaSHeader(mmvRoot);
+            }
+
             if (vNodes.empty() && chainparams.MiningRequiresPeers())
             {
                 if ( Mining_height > ASSETCHAINS_MINHEIGHT )
@@ -1186,6 +1396,10 @@ void static VerusStaker(CWallet *pwallet)
     }
 }
 
+typedef bool (*minefunction)(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
+bool mine_verus_v2(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
+bool mine_verus_v2_port(CBlockHeader &bh, CVerusHashV2bWriter &vhw, uint256 &finalHash, uint256 &target, uint64_t start, uint64_t *count);
+
 void static BitcoinMiner_noeq(CWallet *pwallet)
 #else
 void static BitcoinMiner_noeq()
@@ -1233,9 +1447,6 @@ void static BitcoinMiner_noeq()
     try {
         printf("Mining %s with %s\n", ASSETCHAINS_SYMBOL, ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
 
-        // v1 hash writer
-        CVerusHashWriter ss = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
-
         // v2 hash writer
         CVerusHashV2bWriter ss2 = CVerusHashV2bWriter(SER_GETHASH, PROTOCOL_VERSION);
 
@@ -1245,14 +1456,15 @@ void static BitcoinMiner_noeq()
             waitForPeers(chainparams);
 
             pindexPrev = chainActive.LastTip();
-            MilliSleep(100);
 
-            // prevent forking on startup before the diff algorithm kicks in
-            if (chainparams.MiningRequiresPeers() && (pindexPrev->GetHeight() < 50 || pindexPrev != chainActive.LastTip()))
+            // prevent forking on startup before the diff algorithm kicks in,
+            // but only for a startup Verus test chain. PBaaS chains have the difficulty inherited from
+            // their parent
+            if (chainparams.MiningRequiresPeers() && ((IsVerusActive() && pindexPrev->GetHeight() < 50) || pindexPrev != chainActive.LastTip()))
             {
                 do {
                     pindexPrev = chainActive.LastTip();
-                    MilliSleep(5000 + rand() % 5000);
+                    MilliSleep(3000 + rand() % 3000);
                 } while (pindexPrev != chainActive.LastTip());
             }
 
@@ -1279,8 +1491,9 @@ void static BitcoinMiner_noeq()
             if ( ptr == 0 )
             {
                 static uint32_t counter;
-                if ( counter++ < 100 )
-                    fprintf(stderr,"created illegal block, retry\n");
+                if ( (counter++ < 10) || (counter % 40 == 0) )
+                    fprintf(stderr,"Unable to create valid block... will continue to try\n");
+                MilliSleep(500);
                 continue;
             }
 
@@ -1297,6 +1510,16 @@ void static BitcoinMiner_noeq()
                 return;
             }
             CBlock *pblock = &pblocktemplate->block;
+
+
+
+            uint32_t savebits;
+            bool mergeMining = false;
+            savebits = pblock->nBits;
+
+            bool verusHashV2 = pblock->nVersion == CBlockHeader::VERUS_V2;
+            bool verusSolutionV3 = CConstVerusSolutionVector::Version(pblock->nSolution) == CActivationHeight::SOLUTION_VERUSV3;
+
             if ( ASSETCHAINS_SYMBOL[0] != 0 )
             {
                 if ( ASSETCHAINS_REWARD[0] == 0 && !ASSETCHAINS_LASTERA )
@@ -1311,17 +1534,125 @@ void static BitcoinMiner_noeq()
                     } else fprintf(stderr,"%s vouts.%d mining.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pblock->vtx[0].vout.size(),Mining_height,ASSETCHAINS_MINHEIGHT);
                 }
             }
+
+            // this builds the Merkle tree
             IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
+
+            // update PBaaS header
+            if (verusSolutionV3)
+            {
+                uint256 mmvRoot;
+                {
+                    LOCK(cs_main);
+                    ChainMerkleMountainView mmv = chainActive.GetMMV();
+                    mmvRoot = mmv.GetRoot();
+                }
+                pblock->AddUpdatePBaaSHeader(mmvRoot);
+
+                if (IsVerusActive())
+                {
+                    // combine all merge mined headers into this header
+                    // and get the easiest target of all chains in savebits
+                    if (!(savebits = ConnectedChains.CombineBlocks(*pblock)))
+                    {
+                        savebits = pblock->nBits;
+                    }
+
+                    LOCK(cs_main);
+                    // TODO: REMOVE OR COMMENT TESTS
+                    // tests to validate a few transactions and all past blocks
+                    ChainMerkleMountainView mmv = chainActive.GetMMV();
+                    mmvRoot = mmv.GetRoot();
+                    for (uint32_t i = 1; i <= pindexPrev->GetHeight(); i += 10)
+                    {
+                        CBlockIndex *pindex = chainActive[i - 1];
+                        mmv.resize(i);
+                        uint256 testRoot = mmv.GetRoot();
+                        uint32_t testHeight = ((unsigned char *)&testRoot)[0] < i ? (i - ((unsigned char *)&testRoot)[0]) - 1 : i - 1;
+                        CMerkleBranch branchMerkle, branchBlock;
+                        chainActive.GetBlockProof(mmv, branchBlock, testHeight);
+                        chainActive.GetMerkleProof(mmv, branchMerkle, testHeight);
+                        uint256 merkleAnswer = branchMerkle.SafeCheck(chainActive[testHeight]->hashMerkleRoot);
+                        uint256 blockAnswer = branchBlock.SafeCheck(chainActive[testHeight]->GetBlockHash());
+                        if (merkleAnswer != testRoot)
+                        {
+                            printf("Failed merkle proof at testheight: %u\nexpected:   %s\ncalculated: %s\n", testHeight, testRoot.GetHex().c_str(), merkleAnswer.GetHex().c_str());
+                            printf("Bits for left (0) and right (1): \n");
+                            std::vector<unsigned char> proofBits = ChainMerkleMountainView::GetProofBits(testHeight, i);
+                            printf("right\n");
+                            for (auto bit : proofBits)
+                            {
+                                printf("%s\n", bit ? "left" : "right");
+                            }
+                        }
+                        if (blockAnswer != testRoot)
+                        {
+                            printf("Failed block proof at testheight: %u\nexpected:   %s\ncalculated: %s\n", testHeight, testRoot.GetHex().c_str(), blockAnswer.GetHex().c_str());
+                            printf("Bits for left (0) and right (1): \n");
+                            std::vector<unsigned char> proofBits = ChainMerkleMountainView::GetProofBits(testHeight, i);
+                            printf("left\n");
+                            for (auto bit : proofBits)
+                            {
+                                printf("%s\n", bit ? "left" : "right");
+                            }
+                        }
+                        const CMMRPowerNode *ppower = mmv.GetRootNode();
+                        if (!ppower || ppower->Work() != pindex->chainPower.chainWork)
+                        {
+                            printf("Work did not match:\nexpected:   %s\ncalculated: %s\n", ArithToUint256(pindex->chainPower.chainWork).GetHex().c_str(), ArithToUint256(ppower->Work()).GetHex().c_str());
+                        }
+                        if (!ppower || ppower->Stake() != pindex->chainPower.chainStake)
+                        {
+                            printf("Stake did not match:\nexpected:   %s\ncalculated: %s\n", ArithToUint256(pindex->chainPower.chainStake).GetHex().c_str(), ArithToUint256(ppower->Stake()).GetHex().c_str());
+                        }
+                    }
+                    // END TESTS
+                }
+                else
+                {
+                    // submit the block for merge mining if Verus is present
+                    // otherwise, mine solo
+                    if (ConnectedChains.IsVerusPBaaSAvailable())
+                    {
+
+                        UniValue params(UniValue::VARR);
+                        UniValue error(UniValue::VARR);
+                        params.push_back(EncodeHexBlk(*pblock));
+                        params.push_back(ASSETCHAINS_SYMBOL);
+                        params.push_back(ASSETCHAINS_RPCHOST);
+                        params.push_back(ASSETCHAINS_RPCPORT);
+                        params.push_back(ASSETCHAINS_RPCCREDENTIALS);
+                        try
+                        {
+                            params = RPCCallRoot("addmergedblock", params);
+                            params = find_value(params, "result");
+                            error = find_value(params, "error");
+                        } catch (std::exception e)
+                        {
+                            printf("Failed to connect to %s chain\n", ConnectedChains.notaryChain.chainDefinition.name.c_str());
+                            params = UniValue(e.what());
+                        }
+                        if (mergeMining = (params.isNull() && error.isNull()))
+                        {
+                            printf("Merge mining with %s as the actual mining chain\n", ConnectedChains.notaryChain.chainDefinition.name.c_str());
+                            LogPrintf("Merge mining with %s\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
+                        }
+                    }
+                }
+            }
+
             LogPrintf("Running %s miner with %u transactions in block (%u bytes)\n",ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO],
                        pblock->vtx.size(),::GetSerializeSize(*pblock,SER_NETWORK,PROTOCOL_VERSION));
             //
             // Search
             //
-            uint32_t savebits; int64_t nStart = GetTime();
+            int64_t nStart = GetTime();
 
-            savebits = pblock->nBits;
-            arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
-            arith_uint256 mask(ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO]);
+            arith_uint256 hashTarget = arith_uint256().SetCompact(savebits);
+            uint256 uintTarget = ArithToUint256(hashTarget);
+
+            arith_uint256 ourTarget;
+            ourTarget.SetCompact(pblock->nBits);
 
             Mining_start = 0;
 
@@ -1332,7 +1663,7 @@ void static BitcoinMiner_noeq()
                     lastChainTipPrinted = chainActive.LastTip();
                     printf("Block %d added to chain\n", lastChainTipPrinted->GetHeight());
                 }
-                MilliSleep(250);
+                MilliSleep(100);
                 continue;
             }
 
@@ -1345,84 +1676,119 @@ void static BitcoinMiner_noeq()
                 fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%%\n",percPoS,(int32_t)ASSETCHAINS_STAKED);
             }
 
-            int64_t i, count, hashesToGo;
-            bool verusHashV2 = pblock->nVersion == CBlockHeader::VERUS_V2;
-
-            if (verusHashV2)
-            {
-                count = (ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1;
-            }
-            else
+            uint64_t count, hashesToGo = 0;
+            if (!verusHashV2)
             {
-                count = ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] + 1;
+                // must not be in sync
+                printf("Mining on incorrect block version.\n");
+                sleep(2);
+                continue;
             }
 
-            CVerusHash *vh = &ss.GetState();;
+            count = ((ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1) / ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
             CVerusHashV2 *vh2 = &ss2.GetState();
+            u128 *hashKey;
+            verusclhasher &vclh = vh2->vclh;
+            minefunction mine_verus;
+            mine_verus = IsCPUVerusOptimized() ? &mine_verus_v2 : &mine_verus_v2_port;
 
             while (true)
             {
-                arith_uint256 arNonce = UintToArith256(pblock->nNonce);
-
-                int64_t *extraPtr;
                 uint256 hashResult = uint256();
 
-                hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
-
                 unsigned char *curBuf;
 
-                if (verusHashV2)
+                if (mergeMining)
                 {
-                    vh2->Reset();
-                    ss2 << *((CBlockHeader *)pblock);
-                    extraPtr = ss2.xI64p();
-                    curBuf = vh2->CurBuffer();
-                    vh2->GenNewCLKey(curBuf);
-                }
-                else
-                {
-                    vh->Reset();
-                    ss << *((CBlockHeader *)pblock);
-                    extraPtr = ss.xI64p();
-                    vh->ClearExtra();
-                }
-
-                // for speed check NONCEMASK at a time
-                for (i = 0; i < count; i++)
-                {
-                    *extraPtr = i;
-
-                    uint64_t intermediate;
-
-                    if (verusHashV2)
+                    // loop for about one minute before refreshing the block
+                    while (true)
                     {
-                        // prepare the buffer
-                        vh2->FillExtra((u128 *)curBuf);
+                        // if PBaaS is no longer available, we can't count on merge mining
+                        if (!ConnectedChains.IsVerusPBaaSAvailable())
+                        {
+                            break;
+                        }
+                        boost::this_thread::interruption_point();
+                        MilliSleep(1000);
 
-                        // refresh the key and get a reference
-                        u128 *hashKey = (u128 *)vh2->vclh.gethashkey();
+                        if (vNodes.empty() && chainparams.MiningRequiresPeers())
+                        {
+                            if ( Mining_height > ASSETCHAINS_MINHEIGHT )
+                            {
+                                fprintf(stderr,"no nodes, attempting reconnect\n");
+                                break;
+                            }
+                        }
 
-                        // run verusclhash on the buffer
-                        intermediate = vh2->vclh(hashKey, curBuf);
+                        // update every few minutes, regardless
+                        int64_t elapsed = GetTime() - nStart;
+                        if ((mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && elapsed > 60) || elapsed > 240)
+                        {
+                            break;
+                        }
 
-                        // fill buffer to the end with the result and final hash
-                        vh2->FillExtra(&intermediate);
-                        vh2->ExtraHashKeyed((unsigned char *)&hashResult, hashKey + vh2->IntermediateTo128Offset(intermediate));
-                    }
-                    else
-                    {
-                        vh->ExtraHash((unsigned char *)&hashResult);
+                        if ( pindexPrev != chainActive.LastTip() )
+                        {
+                            if (lastChainTipPrinted != chainActive.LastTip())
+                            {
+                                lastChainTipPrinted = chainActive.LastTip();
+                                printf("Block %d added to chain\n\n", lastChainTipPrinted->GetHeight());
+                            }
+                            break;
+                        }
                     }
-
-                    if ( UintToArith256(hashResult) > hashTarget )
+                    break;
+                }
+                else
+                {
+                    // check NONCEMASK at a time
+                    for (uint64_t i = 0; i < count; i++)
                     {
-                        // check periodically if we're stale
-                        if (--hashesToGo)
+                        // this is the merge mining loop, which enables us to drop out and queue a header anytime we earn a block that is good enough for a
+                        // merge mined block, but not our own
+                        uint64_t totalDone = 0;
+                        bool blockFound;
+                        arith_uint256 arithHash;
+                        do
                         {
-                            continue;
-                        }
-                        else
+                            // hashesToGo gets updated with actual number run for metrics
+                            hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
+                            uint64_t start = i * hashesToGo;
+                            hashesToGo -= totalDone;
+
+                            if (verusSolutionV3)
+                            {
+                                // mine on canonical header for merge mining
+                                CPBaaSPreHeader savedHeader(*pblock);
+                                pblock->ClearNonCanonicalData();
+                                blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
+                                savedHeader.SetBlockData(*pblock);
+                            }
+                            else
+                            {
+                                blockFound = (*mine_verus)(*pblock, ss2, hashResult, uintTarget, start, &hashesToGo);
+                            }
+
+                            arithHash = UintToArith256(hashResult);
+                            totalDone += hashesToGo;
+                            if (blockFound && IsVerusActive())
+                            {
+                                ConnectedChains.QueueNewBlockHeader(*pblock);
+                                if (arithHash > ourTarget)
+                                {
+                                    // all blocks qualified with this hash will be submitted
+                                    // until we redo the block, we might as well not try again with anything over this hash
+                                    hashTarget = arithHash;
+                                    uintTarget = ArithToUint256(hashTarget);
+                                }
+                            }
+                            hashesToGo = totalDone;
+                        } while (blockFound && arithHash > ourTarget);
+
+                        if (!blockFound || arithHash > ourTarget)
                         {
+                            // Check for stop or if block needs to be rebuilt
+                            boost::this_thread::interruption_point();
                             if ( pindexPrev != chainActive.LastTip() )
                             {
                                 if (lastChainTipPrinted != chainActive.LastTip())
@@ -1432,68 +1798,74 @@ void static BitcoinMiner_noeq()
                                 }
                                 break;
                             }
-                            hashesToGo = ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO];
+                            else
+                            {
+                                {
+                                    LOCK(cs_metrics);
+                                    nHashCount += hashesToGo;
+                                }
+                                continue;
+                            }
                         }
-                    }
-                    else
-                    {
-                        // Check for stop or if block needs to be rebuilt
-                        boost::this_thread::interruption_point();
-
-                        if (pblock->nSolution.size() != 1344)
+                        else
                         {
-                            LogPrintf("ERROR: Block solution is not 1344 bytes as it should be");
-                            break;
-                        }
+                            // Check for stop or if block needs to be rebuilt
+                            boost::this_thread::interruption_point();
 
-                        SetThreadPriority(THREAD_PRIORITY_NORMAL);
+                            if (pblock->nSolution.size() != 1344)
+                            {
+                                LogPrintf("ERROR: Block solution is not 1344 bytes as it should be");
+                                break;
+                            }
 
-                        *((int64_t *)&(pblock->nSolution.data()[pblock->nSolution.size() - 15])) = i;
+                            SetThreadPriority(THREAD_PRIORITY_NORMAL);
 
-                        int32_t unlockTime = komodo_block_unlocktime(Mining_height);
-                        int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
+                            int32_t unlockTime = komodo_block_unlocktime(Mining_height);
+                            int64_t subsidy = (int64_t)(pblock->vtx[0].vout[0].nValue);
 
 #ifdef VERUSHASHDEBUG
-                        std::string validateStr = hashResult.GetHex();
-                        std::string hashStr = pblock->GetHash().GetHex();
-                        uint256 *bhalf1 = (uint256 *)vh2->CurBuffer();
-                        uint256 *bhalf2 = bhalf1 + 1;
+                            std::string validateStr = hashResult.GetHex();
+                            std::string hashStr = pblock->GetHash().GetHex();
+                            uint256 *bhalf1 = (uint256 *)vh2->CurBuffer();
+                            uint256 *bhalf2 = bhalf1 + 1;
 #else
-                        std::string hashStr = hashResult.GetHex();
+                            std::string hashStr = hashResult.GetHex();
 #endif
 
-                        LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
-                        LogPrintf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", hashStr, hashTarget.GetHex());
-                        printf("Found block %d \n", Mining_height );
-                        printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
+                            LogPrintf("Using %s algorithm:\n", ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]);
+                            LogPrintf("proof-of-work found  \n  hash: %s  \ntarget: %s\n", hashStr, ArithToUint256(ourTarget).GetHex());
+                            printf("Found block %d \n", Mining_height );
+                            printf("mining reward %.8f %s!\n", (double)subsidy / (double)COIN, ASSETCHAINS_SYMBOL);
 #ifdef VERUSHASHDEBUG
-                        printf("  hash: %s\n   val: %s  \ntarget: %s\n\n", hashStr.c_str(), validateStr.c_str(), hashTarget.GetHex().c_str());
-                        printf("intermediate %lx\n", intermediate);
-                        printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
-                        bhalf1 = (uint256 *)verusclhasher_key.get();
-                        bhalf2 = bhalf1 + ((vh2->vclh.keyMask + 1) >> 5);
-                        printf("   Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
+                            printf("  hash: %s\n   val: %s  \ntarget: %s\n\n", hashStr.c_str(), validateStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
+                            printf("intermediate %lx\n", intermediate);
+                            printf("Curbuf: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
+                            bhalf1 = (uint256 *)verusclhasher_key.get();
+                            bhalf2 = bhalf1 + ((vh2->vclh.keyMask + 1) >> 5);
+                            printf("   Key: %s%s\n", bhalf1->GetHex().c_str(), bhalf2->GetHex().c_str());
 #else
-                        printf("  hash: %s\ntarget: %s", hashStr.c_str(), hashTarget.GetHex().c_str());
+                            printf("  hash: %s\ntarget: %s", hashStr.c_str(), ArithToUint256(ourTarget).GetHex().c_str());
 #endif
-                        if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
-                            printf(" - timelocked until block %i\n", unlockTime);
-                        else
-                            printf("\n");
+                            if (unlockTime > Mining_height && subsidy >= ASSETCHAINS_TIMELOCKGTE)
+                                printf(" - timelocked until block %i\n", unlockTime);
+                            else
+                                printf("\n");
 #ifdef ENABLE_WALLET
-                        ProcessBlockFound(pblock, *pwallet, reservekey);
+                            ProcessBlockFound(pblock, *pwallet, reservekey);
 #else
-                        ProcessBlockFound(pblock));
+                            ProcessBlockFound(pblock);
 #endif
-                        SetThreadPriority(THREAD_PRIORITY_LOWEST);
-                        break;
+                            SetThreadPriority(THREAD_PRIORITY_LOWEST);
+                            break;
+                        }
                     }
-                }
 
-                {
-                    LOCK(cs_metrics);
-                    nHashCount += i;
+                    {
+                        LOCK(cs_metrics);
+                        nHashCount += hashesToGo;
+                    }
                 }
+                
 
                 // Check for stop or if block needs to be rebuilt
                 boost::this_thread::interruption_point();
@@ -1524,9 +1896,9 @@ void static BitcoinMiner_noeq()
                 }
 
 #ifdef _WIN32
-                printf("%llu mega hashes complete - working\n", count / 1048576);
+                printf("%llu mega hashes complete - working\n", ((ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1) / 1048576);
 #else
-                printf("%lu mega hashes complete - working\n", count / 1048576);
+                printf("%lu mega hashes complete - working\n", ((ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] >> 3) + 1) / 1048576);
 #endif
                 break;
 
@@ -2018,6 +2390,11 @@ void static BitcoinMiner()
     void GenerateBitcoins(bool fGenerate, int nThreads)
 #endif
     {
+        if (!AreParamsInitialized())
+        {
+            return;
+        }
+
         // if we are supposed to catch stake cheaters, there must be a valid sapling parameter, we need it at
         // initialization, and this is the first time we can get it. store the Sapling address here
         extern boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
@@ -2033,22 +2410,30 @@ void static BitcoinMiner()
             {
             }
         }
-        if (fGenerate == true && VERUS_CHEATCATCHER.size() > 0)
+
+        VERUS_MINTBLOCKS = (VERUS_MINTBLOCKS && ASSETCHAINS_LWMAPOS != 0);
+
+        if (fGenerate == true || VERUS_MINTBLOCKS)
         {
-            if (cheatCatcher == boost::none)
-            {
-                LogPrintf("ERROR: -cheatcatcher parameter is invalid Sapling payment address\n");
-                fprintf(stderr, "-cheatcatcher parameter is invalid Sapling payment address\n");
-            }
-            else
+            mapArgs["-gen"] = "1";
+
+            if (VERUS_CHEATCATCHER.size() > 0)
             {
-                LogPrintf("StakeGuard searching for double stakes on %s\n", VERUS_CHEATCATCHER.c_str());
-                fprintf(stderr, "StakeGuard searching for double stakes on %s\n", VERUS_CHEATCATCHER.c_str());
+                if (cheatCatcher == boost::none)
+                {
+                    LogPrintf("ERROR: -cheatcatcher parameter is invalid Sapling payment address\n");
+                    fprintf(stderr, "-cheatcatcher parameter is invalid Sapling payment address\n");
+                }
+                else
+                {
+                    LogPrintf("StakeGuard searching for double stakes on %s\n", VERUS_CHEATCATCHER.c_str());
+                    fprintf(stderr, "StakeGuard searching for double stakes on %s\n", VERUS_CHEATCATCHER.c_str());
+                }
             }
         }
 
         static boost::thread_group* minerThreads = NULL;
-        
+
         if (nThreads < 0)
             nThreads = GetNumCores();
         
@@ -2063,13 +2448,16 @@ void static BitcoinMiner()
         if ( nThreads == 0 && ASSETCHAINS_STAKED )
             nThreads = 1;
 
-        if ((nThreads == 0 || !fGenerate) && (VERUS_MINTBLOCKS == 0 || pwallet == NULL))
+        if (!fGenerate)
             return;
 
         minerThreads = new boost::thread_group();
 
+        // add the PBaaS thread when mining or staking
+        minerThreads->create_thread(boost::bind(&CConnectedChains::SubmissionThreadStub));
+
 #ifdef ENABLE_WALLET
-        if (ASSETCHAINS_LWMAPOS != 0 && VERUS_MINTBLOCKS)
+        if (VERUS_MINTBLOCKS && pwallet != NULL)
         {
             minerThreads->create_thread(boost::bind(&VerusStaker, pwallet));
         }
This page took 0.050213 seconds and 4 git commands to generate.