LCOV - code coverage report
Current view: top level - src - kernel.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 60 66 90.9 %
Date: 2025-02-23 09:33:43 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2013 The PPCoin developers
       2             : // Copyright (c) 2013-2014 The NovaCoin Developers
       3             : // Copyright (c) 2014-2018 The BlackCoin Developers
       4             : // Copyright (c) 2015-2021 The PIVX Core developers
       5             : // Distributed under the MIT/X11 software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #include "kernel.h"
       9             : 
      10             : #include "db.h"
      11             : #include "legacy/stakemodifier.h"
      12             : #include "policy/policy.h"
      13             : #include "script/interpreter.h"
      14             : #include "stakeinput.h"
      15             : #include "util/system.h"
      16             : #include "utilmoneystr.h"
      17             : #include "validation.h"
      18             : #include "zpiv/zpos.h"
      19             : 
      20             : /**
      21             :  * CStakeKernel Constructor
      22             :  *
      23             :  * @param[in]   pindexPrev      index of the parent of the kernel block
      24             :  * @param[in]   stakeInput      input for the coinstake of the kernel block
      25             :  * @param[in]   nBits           target difficulty bits of the kernel block
      26             :  * @param[in]   nTimeTx         time of the kernel block
      27             :  */
      28       19490 : CStakeKernel::CStakeKernel(const CBlockIndex* const pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int nTimeTx):
      29       19490 :     stakeUniqueness(stakeInput->GetUniqueness()),
      30             :     nTime(nTimeTx),
      31             :     nBits(nBits),
      32       19490 :     stakeValue(stakeInput->GetValue())
      33             : {
      34             :     // Set kernel stake modifier
      35       19490 :     if (!Params().GetConsensus().NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_V3_4)) {
      36         244 :         uint64_t nStakeModifier = 0;
      37         244 :         if (!GetOldStakeModifier(stakeInput, nStakeModifier))
      38           0 :             LogPrintf("%s : ERROR: Failed to get kernel stake modifier\n", __func__);
      39             :         // Modifier v1
      40         244 :         stakeModifier << nStakeModifier;
      41             :     } else {
      42             :         // Modifier v2
      43       38492 :         stakeModifier << pindexPrev->GetStakeModifierV2();
      44             :     }
      45       19490 :     const CBlockIndex* pindexFrom = stakeInput->GetIndexFrom();
      46       19490 :     nTimeBlockFrom = pindexFrom->nTime;
      47       19490 : }
      48             : 
      49             : // Return stake kernel hash
      50       19490 : uint256 CStakeKernel::GetHash() const
      51             : {
      52       19490 :     CDataStream ss(stakeModifier);
      53       19490 :     ss << nTimeBlockFrom << stakeUniqueness << nTime;
      54       38980 :     return Hash(ss.begin(), ss.end());
      55             : }
      56             : 
      57             : // Check that the kernel hash meets the target required
      58       19446 : bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
      59             : {
      60             :     // Get weighted target
      61       19446 :     arith_uint256 bnTarget;
      62       19446 :     bnTarget.SetCompact(nBits);
      63       58338 :     bnTarget *= (arith_uint256(stakeValue) / 100);
      64             : 
      65             :     // Check PoS kernel hash
      66       19446 :     const arith_uint256& hashProofOfStake = UintToArith256(GetHash());
      67       19446 :     const bool res = hashProofOfStake < bnTarget;
      68             : 
      69       19446 :     if (!fSkipLog || res) {
      70       42783 :         LogPrint(BCLog::STAKING, "%s : Proof Of Stake:" /* Continued */
      71             :                             "\nstakeModifier=%s" /* Continued */
      72             :                             "\nnTimeBlockFrom=%d" /* Continued */
      73             :                             "\nssUniqueID=%s" /* Continued */
      74             :                             "\nnTimeTx=%d" /* Continued */
      75             :                             "\nhashProofOfStake=%s" /* Continued */
      76             :                             "\nnBits=%d" /* Continued */
      77             :                             "\nweight=%d" /* Continued */
      78             :                             "\nbnTarget=%s (res: %d)\n\n",
      79             :             __func__, HexStr(stakeModifier), nTimeBlockFrom, HexStr(stakeUniqueness), nTime, hashProofOfStake.GetHex(),
      80             :             nBits, stakeValue, bnTarget.GetHex(), res);
      81             :     }
      82       19446 :     return res;
      83             : }
      84             : 
      85             : 
      86             : /*
      87             :  * PoS Validation
      88             :  */
      89             : 
      90             : // helper function for CheckProofOfStake and GetStakeKernelHash
      91        6764 : static bool LoadStakeInput(const CBlock& block, std::unique_ptr<CStakeInput>& stake, int nHeight)
      92             : {
      93             :     // Check that this is a PoS block
      94        6764 :     if (!block.IsProofOfStake())
      95           0 :         return error("called on non PoS block");
      96             : 
      97             :     // Construct the stakeinput object
      98        6764 :     const CTxIn& txin = block.vtx[1]->vin[0];
      99       13528 :     stake = txin.IsZerocoinSpend() ?
     100           0 :             std::unique_ptr<CStakeInput>(CLegacyZPivStake::NewZPivStake(txin, nHeight)) :
     101       13528 :             std::unique_ptr<CStakeInput>(CPivStake::NewPivStake(txin, nHeight, block.nTime));
     102             : 
     103        6764 :     return stake != nullptr;
     104             : }
     105             : 
     106             : /*
     107             :  * Stake                Check if stakeInput can stake a block on top of pindexPrev
     108             :  *
     109             :  * @param[in]   pindexPrev      index of the parent block of the block being staked
     110             :  * @param[in]   stakeInput      input for the coinstake
     111             :  * @param[in]   nBits           target difficulty bits
     112             :  * @param[in]   nTimeTx         new blocktime
     113             :  * @return      bool            true if stake kernel hash meets target protocol
     114             :  */
     115       12726 : bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx)
     116             : {
     117       12726 :     if (!stakeInput) return false;
     118             : 
     119             :     // Get the new time slot (and verify it's not the same as previous block)
     120       12726 :     const bool fRegTest = Params().IsRegTestNet();
     121       12726 :     nTimeTx = (fRegTest ? GetAdjustedTime() : GetCurrentTimeSlot());
     122       12726 :     if (nTimeTx <= pindexPrev->nTime && !fRegTest) return false;
     123             : 
     124             :     // Verify Proof Of Stake
     125       25452 :     CStakeKernel stakeKernel(pindexPrev, stakeInput, nBits, nTimeTx);
     126       12726 :     return stakeKernel.CheckKernelHash(true);
     127             : }
     128             : 
     129             : 
     130             : /*
     131             :  * CheckProofOfStake    Check if block has valid proof of stake
     132             :  *
     133             :  * @param[in]   block           block being verified
     134             :  * @param[out]  strError        string error (if any, else empty)
     135             :  * @param[in]   pindexPrev      index of the parent block
     136             :  *                              (if nullptr, it will be searched in mapBlockIndex)
     137             :  * @return      bool            true if the block has a valid proof of stake
     138             :  */
     139        6720 : bool CheckProofOfStake(const CBlock& block, std::string& strError, const CBlockIndex* pindexPrev)
     140             : {
     141        6720 :     const int nHeight = pindexPrev->nHeight + 1;
     142             :     // Initialize stake input
     143        6720 :     std::unique_ptr<CStakeInput> stakeInput;
     144        6720 :     if (!LoadStakeInput(block, stakeInput, nHeight)) {
     145           0 :         strError = "stake input initialization failed";
     146             :         return false;
     147             :     }
     148             : 
     149             :     // Verify Proof Of Stake
     150       13440 :     CStakeKernel stakeKernel(pindexPrev, stakeInput.get(), block.nBits, block.nTime);
     151        6720 :     if (!stakeKernel.CheckKernelHash()) {
     152           0 :         strError = "kernel hash check fails";
     153             :         return false;
     154             :     }
     155             : 
     156             :     // zPoS disabled (ContextCheck) before blocks V7, and the tx input signature is in CoinSpend
     157        6720 :     if (stakeInput->IsZPIV()) return true;
     158             : 
     159             :     // Verify tx input signature
     160       13440 :     CTxOut stakePrevout;
     161        6720 :     if (!stakeInput->GetTxOutFrom(stakePrevout)) {
     162        6720 :         strError = "unable to get stake prevout for coinstake";
     163             :         return false;
     164             :     }
     165        6720 :     const auto& tx = block.vtx[1];
     166        6720 :     const CTxIn& txin = tx->vin[0];
     167        6720 :     ScriptError serror;
     168       13440 :     if (!VerifyScript(txin.scriptSig, stakePrevout.scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS,
     169        6720 :              TransactionSignatureChecker(tx.get(), 0, stakePrevout.nValue), tx->GetRequiredSigVersion(), &serror)) {
     170           1 :         strError = strprintf("signature fails: %s", serror ? ScriptErrorString(serror) : "");
     171           1 :         return false;
     172             :     }
     173             : 
     174             :     // All good
     175             :     return true;
     176             : }
     177             : 
     178             : 
     179             : /*
     180             :  * GetStakeKernelHash   Return stake kernel of a block
     181             :  *
     182             :  * @param[out]  hashRet         hash of the kernel (set by this function)
     183             :  * @param[in]   block           block with the kernel to return
     184             :  * @param[in]   pindexPrev      index of the parent block
     185             :  *                              (if nullptr, it will be searched in mapBlockIndex)
     186             :  * @return      bool            false if kernel cannot be initialized, true otherwise
     187             :  */
     188          44 : bool GetStakeKernelHash(uint256& hashRet, const CBlock& block, const CBlockIndex* pindexPrev)
     189             : {
     190             :     // Initialize stake input
     191          44 :     std::unique_ptr<CStakeInput> stakeInput;
     192          44 :     if (!LoadStakeInput(block, stakeInput, pindexPrev->nHeight + 1))
     193           0 :         return error("%s : stake input initialization failed", __func__);
     194             : 
     195          88 :     CStakeKernel stakeKernel(pindexPrev, stakeInput.get(), block.nBits, block.nTime);
     196          44 :     hashRet = stakeKernel.GetHash();
     197          44 :     return true;
     198             : }
     199             : 

Generated by: LCOV version 1.14