diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 8663a0c0a..1ef813085 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -80,8 +80,10 @@ uint32_t ASSETCHAINS_ALGO = _ASSETCHAINS_EQUIHASH; // Verus proof of stake controls int32_t ASSETCHAINS_LWMAPOS = 0; // percentage of blocks should be PoS -int32_t VERUS_BLOCK_POSUNITS = 1000; // one block is 1000 units +int32_t VERUS_BLOCK_POSUNITS = 1024; // one block is 1000 units int32_t VERUS_MIN_STAKEAGE = 150; // 1/2 this should also be a cap on the POS averaging window, or startup could be too easy +int32_t VERUS_MAX_CONSECUTIVE_POS = 7; +int32_t VERUS_NOPOS_THRESHHOLD = 150; // if we have no POS blocks in this many blocks, set to default difficulty uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10; diff --git a/src/main.cpp b/src/main.cpp index 03eaa0647..b0e66e391 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5622,10 +5622,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); return true; } - - - - + if (strCommand == "version") { // Each connection can only send one version message diff --git a/src/miner.cpp b/src/miner.cpp index deeeeab76..94aa9bf71 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1017,23 +1017,19 @@ void static BitcoinMiner_noeq() waitForPeers(chainparams); CBlockIndex *pindexPrev, *pindexCur; do { - { - LOCK(cs_main); - pindexPrev = chainActive.Tip(); - } + pindexPrev = chainActive.Tip(); MilliSleep(5000 + rand() % 5000); - { - LOCK(cs_main); - pindexCur = chainActive.Tip(); - } + pindexCur = chainActive.Tip(); } while (pindexPrev != pindexCur); - printf("Mining height %d\n", chainActive.Tip()->nHeight + 1); + // this will not stop printing more than once in all cases, but it will allow us to print in all cases + // and print duplicates rarely without having to synchronize + static CBlockIndex *lastChainTipPrinted; miningTimer.start(); try { - fprintf(stderr,"Mining %s with %s\n", ASSETCHAINS_SYMBOL, ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]); + printf("Mining %s with %s\n", ASSETCHAINS_SYMBOL, ASSETCHAINS_ALGORITHMS[ASSETCHAINS_ALGO]); while (true) { miningTimer.stop(); @@ -1050,7 +1046,6 @@ void static BitcoinMiner_noeq() MilliSleep(5000 + rand() % 5000); } while (pindexPrev != chainActive.Tip()); } - miningTimer.start(); // Create new block unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); @@ -1060,7 +1055,13 @@ void static BitcoinMiner_noeq() Mining_start = (uint32_t)time(NULL); } - //fprintf(stderr,"%s create new block ht.%d\n",ASSETCHAINS_SYMBOL,Mining_height); + if (lastChainTipPrinted != pindexPrev) + { + printf("Mining height %d\n", Mining_height); + lastChainTipPrinted = pindexPrev; + } + + miningTimer.start(); #ifdef ENABLE_WALLET CBlockTemplate *ptr = CreateNewBlockWithKey(reservekey); @@ -1074,6 +1075,7 @@ void static BitcoinMiner_noeq() fprintf(stderr,"created illegal block, retry\n"); continue; } + unique_ptr pblocktemplate(ptr); if (!pblocktemplate.get()) { @@ -1118,7 +1120,11 @@ void static BitcoinMiner_noeq() if ( pindexPrev != chainActive.Tip() ) { - printf("Block %d added to chain\n", chainActive.Tip()->nHeight); + if (lastChainTipPrinted != chainActive.Tip()) + { + lastChainTipPrinted = chainActive.Tip(); + printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); + } MilliSleep(250); continue; } @@ -1134,13 +1140,17 @@ void static BitcoinMiner_noeq() while (true) { - // for speed check multiples at a time - for (int i = 0; i < ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO]; i++) + arith_uint256 arNonce = UintToArith256(pblock->nNonce); + + // for speed check 16 mega hash at a time + for (int i = 0; i < 0x1000000; i++) { solutionTargetChecks.increment(); - // Update nNonce and nTime - pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); + // Update nNonce + *((unsigned char *)&(pblock->nNonce)) = i & 0xff; + *(((unsigned char *)&(pblock->nNonce))+1) = (i >> 8) & 0xff; + *(((unsigned char *)&(pblock->nNonce))+2) = (i >> 16) & 0xff; if ( UintToArith256(pblock->GetHash()) <= hashTarget ) { @@ -1165,17 +1175,18 @@ void static BitcoinMiner_noeq() ProcessBlockFound(pblock)); #endif SetThreadPriority(THREAD_PRIORITY_LOWEST); - - // In regression test mode, stop mining after a block is found. - if (chainparams.MineBlocksOnDemand()) { - throw boost::thread_interrupted(); - } break; } - else + // check periodically if we're stale + if (!(i % ASSETCHAINS_HASHESPERROUND[ASSETCHAINS_ALGO])) { - if ((UintToArith256(pblock->nNonce) & mask) == mask) + if ( pindexPrev != chainActive.Tip() ) { + if (lastChainTipPrinted != chainActive.Tip()) + { + lastChainTipPrinted = chainActive.Tip(); + printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); + } break; } } @@ -1193,12 +1204,6 @@ void static BitcoinMiner_noeq() } } - if ((UintToArith256(pblock->nNonce) & mask) == mask) - { - fprintf(stderr,"%lu mega hashes complete - working\n", (ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] + 1) / 1048576); - break; - } - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) { fprintf(stderr,"timeout, retrying\n"); @@ -1207,7 +1212,17 @@ void static BitcoinMiner_noeq() if ( pindexPrev != chainActive.Tip() ) { - printf("Block %d added to chain\n", chainActive.Tip()->nHeight); + if (lastChainTipPrinted != chainActive.Tip()) + { + lastChainTipPrinted = chainActive.Tip(); + printf("Block %d added to chain\n", lastChainTipPrinted->nHeight); + } + break; + } + + if ((UintToArith256(pblock->nNonce) & mask) == mask) + { + printf("%lu mega hashes complete - working\n", (ASSETCHAINS_NONCEMASK[ASSETCHAINS_ALGO] + 1) / 1048576); break; } diff --git a/src/pow.cpp b/src/pow.cpp index 49d03d5c2..330504eba 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -22,7 +22,7 @@ uint32_t komodo_chainactive_timestamp(); extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH; -extern int32_t VERUS_BLOCK_POSUNITS; +extern int32_t VERUS_BLOCK_POSUNITS, VERUS_MAX_CONSECUTIVE_POS, VERUS_NOPOS_THRESHHOLD; unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params); @@ -157,55 +157,131 @@ bool DoesHashQualify(const CBlockIndex *pbindex) // the goal is to keep POS at a solve time that is a ratio of block time units. the low resolution makes a stable solution more challenging // and requires that the averaging window be quite long. -unsigned int lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params) +uint32_t lwmaGetNextPOSRequired(const CBlockIndex* pindexLast, const Consensus::Params& params) { arith_uint256 nextTarget {0}, sumTarget {0}, bnTmp, bnLimit; bnLimit = UintToArith256(params.posLimit); - unsigned int nProofOfStakeLimit = bnLimit.GetCompact(); + uint32_t nProofOfStakeLimit = bnLimit.GetCompact(); + int64_t t = 0, solvetime = 0; + int64_t k = params.nLwmaPOSAjustedWeight; + int64_t N = params.nPOSAveragingWindow; + + struct solveSequence { + bool consecutive; + uint32_t solveTime; + uint32_t nBits; + solveSequence() + { + consecutive = 0; + solveTime = 0; + nBits = 0; + } + }; // Find the first block in the averaging interval as we total the linearly weighted average // of POS solve times const CBlockIndex* pindexFirst = pindexLast; - const CBlockIndex* pindexNext; + std::vector idx; - int64_t t = 0, solvetime = 0, k = params.nLwmaPOSAjustedWeight, N = params.nPOSAveragingWindow; - - for (int i = 0, j = N - 1; pindexFirst && i < N; i++, j--) { - pindexNext = pindexFirst; - // we measure our solve time in passing of blocks, where one bock == VERUS_BLOCK_POSUNITS units - for (int x = 0; x < params.nPOSAveragingWindow; x++) - { - solvetime += VERUS_BLOCK_POSUNITS; - pindexFirst = pindexFirst->pprev; - // in this loop, unqualified blocks are assumed POS - if (!pindexFirst || !DoesHashQualify(pindexFirst)) - break; - } + // we need to make sure we have a starting nBits reference, which is either the last POS block, or the default + // if we have had no POS block in the threshold number of blocks, we must return the default, otherwise, we'll now have + // a starting point + uint32_t nBits = nProofOfStakeLimit; + for (int i = 0; i < VERUS_NOPOS_THRESHHOLD; i++) + { if (!pindexFirst) - break; + return nProofOfStakeLimit; + CBlockHeader hdr = pindexFirst->GetBlockHeader(); + + if (hdr.IsVerusPOSBlock()) + { + nBits = hdr.GetVerusPOSTarget(); + break; + } + pindexFirst = pindexFirst->pprev; + } + + pindexFirst = pindexLast; + idx.resize(N); + + for (int i = N - 1; i >= 0; i--) + { + // we measure our solve time in passing of blocks, where one bock == VERUS_BLOCK_POSUNITS units + // consecutive blocks in either direction have their solve times exponentially multiplied or divided by power of 2 + int x; + for (x = 0; x < VERUS_MAX_CONSECUTIVE_POS; x++) + { + pindexFirst = pindexFirst->pprev; + + if (!pindexFirst) + return nProofOfStakeLimit; + + CBlockHeader hdr = pindexFirst->GetBlockHeader(); + if (hdr.IsVerusPOSBlock()) + { + nBits = hdr.GetVerusPOSTarget(); + break; + } + } + + if (x) + { + idx[i].consecutive = false; + idx[i].solveTime = VERUS_BLOCK_POSUNITS << x; + idx[i].nBits = nBits; + } + else + { + idx[i].consecutive = true; + idx[i].nBits = nBits; + // go forward and halve the minimum solve time for all consecutive blocks in this run, to get here, our last block is POS, + // and if there is no POS block in front of it, it gets the normal solve time of one block + uint32_t st = VERUS_BLOCK_POSUNITS << 1; + for (int j = i; j < N; j++) + { + if (idx[j].consecutive == true) + { + st >>= 1; + } + else + break; + } + for (int j = i; j < N; j++) + { + if (idx[j].consecutive == true) + idx[j].solveTime = st; + if ((j - i) >= VERUS_MAX_CONSECUTIVE_POS) + { + // target of 0 (virtually impossible), if we hit max consecutive POS blocks + nextTarget.SetCompact(0); + return nextTarget.GetCompact(); + } + else + break; + } + } + } + + for (int i = N - 1; i >= 0; i--) + { // weighted sum - t += solvetime * j; + t += idx[i].solveTime * i; // Target sum divided by a factor, (k N^2). // The factor is a part of the final equation. However we divide // here to avoid potential overflow. - bnTmp.SetCompact(pindexNext->nBits); // TODO(miketout): this must be POS nBits + bnTmp.SetCompact(idx[i].nBits); sumTarget += bnTmp / (k * N * N); } - // Check we have enough blocks - if (!pindexFirst) - return nProofOfStakeLimit; - // Keep t reasonable in case strange solvetimes occurred. if (t < N * k / 3) t = N * k / 3; - bnTmp = bnLimit; nextTarget = t * sumTarget; - if (nextTarget > bnTmp) - nextTarget = bnTmp; + if (nextTarget > bnLimit) + nextTarget = bnLimit; return nextTarget.GetCompact(); }