PIVX Core  5.6.99
P2P Digital Currency
kernel.cpp
Go to the documentation of this file.
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 
28 CStakeKernel::CStakeKernel(const CBlockIndex* const pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int nTimeTx):
29  stakeUniqueness(stakeInput->GetUniqueness()),
30  nTime(nTimeTx),
31  nBits(nBits),
32  stakeValue(stakeInput->GetValue())
33 {
34  // Set kernel stake modifier
35  if (!Params().GetConsensus().NetworkUpgradeActive(pindexPrev->nHeight + 1, Consensus::UPGRADE_V3_4)) {
36  uint64_t nStakeModifier = 0;
37  if (!GetOldStakeModifier(stakeInput, nStakeModifier))
38  LogPrintf("%s : ERROR: Failed to get kernel stake modifier\n", __func__);
39  // Modifier v1
40  stakeModifier << nStakeModifier;
41  } else {
42  // Modifier v2
43  stakeModifier << pindexPrev->GetStakeModifierV2();
44  }
45  const CBlockIndex* pindexFrom = stakeInput->GetIndexFrom();
46  nTimeBlockFrom = pindexFrom->nTime;
47 }
48 
49 // Return stake kernel hash
51 {
54  return Hash(ss.begin(), ss.end());
55 }
56 
57 // Check that the kernel hash meets the target required
58 bool CStakeKernel::CheckKernelHash(bool fSkipLog) const
59 {
60  // Get weighted target
61  arith_uint256 bnTarget;
62  bnTarget.SetCompact(nBits);
63  bnTarget *= (arith_uint256(stakeValue) / 100);
64 
65  // Check PoS kernel hash
66  const arith_uint256& hashProofOfStake = UintToArith256(GetHash());
67  const bool res = hashProofOfStake < bnTarget;
68 
69  if (!fSkipLog || res) {
70  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  return res;
83 }
84 
85 
86 /*
87  * PoS Validation
88  */
89 
90 // helper function for CheckProofOfStake and GetStakeKernelHash
91 static bool LoadStakeInput(const CBlock& block, std::unique_ptr<CStakeInput>& stake, int nHeight)
92 {
93  // Check that this is a PoS block
94  if (!block.IsProofOfStake())
95  return error("called on non PoS block");
96 
97  // Construct the stakeinput object
98  const CTxIn& txin = block.vtx[1]->vin[0];
99  stake = txin.IsZerocoinSpend() ?
100  std::unique_ptr<CStakeInput>(CLegacyZPivStake::NewZPivStake(txin, nHeight)) :
101  std::unique_ptr<CStakeInput>(CPivStake::NewPivStake(txin, nHeight, block.nTime));
102 
103  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 bool Stake(const CBlockIndex* pindexPrev, CStakeInput* stakeInput, unsigned int nBits, int64_t& nTimeTx)
116 {
117  if (!stakeInput) return false;
118 
119  // Get the new time slot (and verify it's not the same as previous block)
120  const bool fRegTest = Params().IsRegTestNet();
121  nTimeTx = (fRegTest ? GetAdjustedTime() : GetCurrentTimeSlot());
122  if (nTimeTx <= pindexPrev->nTime && !fRegTest) return false;
123 
124  // Verify Proof Of Stake
125  CStakeKernel stakeKernel(pindexPrev, stakeInput, nBits, nTimeTx);
126  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 bool CheckProofOfStake(const CBlock& block, std::string& strError, const CBlockIndex* pindexPrev)
140 {
141  const int nHeight = pindexPrev->nHeight + 1;
142  // Initialize stake input
143  std::unique_ptr<CStakeInput> stakeInput;
144  if (!LoadStakeInput(block, stakeInput, nHeight)) {
145  strError = "stake input initialization failed";
146  return false;
147  }
148 
149  // Verify Proof Of Stake
150  CStakeKernel stakeKernel(pindexPrev, stakeInput.get(), block.nBits, block.nTime);
151  if (!stakeKernel.CheckKernelHash()) {
152  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  if (stakeInput->IsZPIV()) return true;
158 
159  // Verify tx input signature
160  CTxOut stakePrevout;
161  if (!stakeInput->GetTxOutFrom(stakePrevout)) {
162  strError = "unable to get stake prevout for coinstake";
163  return false;
164  }
165  const auto& tx = block.vtx[1];
166  const CTxIn& txin = tx->vin[0];
167  ScriptError serror;
168  if (!VerifyScript(txin.scriptSig, stakePrevout.scriptPubKey, STANDARD_SCRIPT_VERIFY_FLAGS,
169  TransactionSignatureChecker(tx.get(), 0, stakePrevout.nValue), tx->GetRequiredSigVersion(), &serror)) {
170  strError = strprintf("signature fails: %s", serror ? ScriptErrorString(serror) : "");
171  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 bool GetStakeKernelHash(uint256& hashRet, const CBlock& block, const CBlockIndex* pindexPrev)
189 {
190  // Initialize stake input
191  std::unique_ptr<CStakeInput> stakeInput;
192  if (!LoadStakeInput(block, stakeInput, pindexPrev->nHeight + 1))
193  return error("%s : stake input initialization failed", __func__);
194 
195  CStakeKernel stakeKernel(pindexPrev, stakeInput.get(), block.nBits, block.nTime);
196  hashRet = stakeKernel.GetHash();
197  return true;
198 }
199 
arith_uint256 UintToArith256(const uint256 &a)
const CChainParams & Params()
Return the currently selected parameters.
const_iterator end() const
Definition: streams.h:163
const_iterator begin() const
Definition: streams.h:161
uint32_t nBits
Definition: block.h:31
uint32_t nTime
Definition: block.h:30
Definition: block.h:80
std::vector< CTransactionRef > vtx
Definition: block.h:83
bool IsProofOfStake() const
Definition: block.h:134
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
uint256 GetStakeModifierV2() const
Definition: chain.cpp:289
uint32_t nTime
Definition: chain.h:196
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
bool IsRegTestNet() const
Definition: chainparams.h:98
static CLegacyZPivStake * NewZPivStake(const CTxIn &txin, int nHeight)
Definition: zpos.cpp:58
virtual const CBlockIndex * GetIndexFrom() const =0
unsigned int nBits
Definition: kernel.h:38
CDataStream stakeModifier
Definition: kernel.h:33
bool CheckKernelHash(bool fSkipLog=false) const
Definition: kernel.cpp:58
CDataStream stakeUniqueness
Definition: kernel.h:35
uint256 GetHash() const
Definition: kernel.cpp:50
CStakeKernel(const CBlockIndex *const pindexPrev, CStakeInput *stakeInput, unsigned int nBits, int nTimeTx)
CStakeKernel Constructor.
Definition: kernel.cpp:28
int nTimeBlockFrom
Definition: kernel.h:34
CAmount stakeValue
Definition: kernel.h:39
int nTime
Definition: kernel.h:36
An input of a transaction.
Definition: transaction.h:94
bool IsZerocoinSpend() const
Definition: transaction.cpp:43
CScript scriptSig
Definition: transaction.h:97
An output of a transaction.
Definition: transaction.h:137
CScript scriptPubKey
Definition: transaction.h:140
CAmount nValue
Definition: transaction.h:139
256-bit unsigned big integer.
arith_uint256 & SetCompact(uint32_t nCompact, bool *pfNegative=nullptr, bool *pfOverflow=nullptr)
The "compact" format is a representation of a whole number N using an unsigned 32bit number similar t...
std::string GetHex() const
256-bit opaque blob.
Definition: uint256.h:138
uint256 Hash(const T1 pbegin, const T1 pend)
Compute the 256-bit hash of an object.
Definition: hash.h:173
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, unsigned int flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptError *serror)
bool CheckProofOfStake(const CBlock &block, std::string &strError, const CBlockIndex *pindexPrev)
Definition: kernel.cpp:139
bool Stake(const CBlockIndex *pindexPrev, CStakeInput *stakeInput, unsigned int nBits, int64_t &nTimeTx)
Definition: kernel.cpp:115
bool GetStakeKernelHash(uint256 &hashRet, const CBlock &block, const CBlockIndex *pindexPrev)
Definition: kernel.cpp:188
#define LogPrint(category,...)
Definition: logging.h:163
@ STAKING
Definition: logging.h:58
@ UPGRADE_V3_4
Definition: params.h:34
Definition: uint256.h:212
const char * ScriptErrorString(const ScriptError serror)
Definition: script_error.cpp:9
enum ScriptError_t ScriptError
bool GetOldStakeModifier(CStakeInput *stake, uint64_t &nStakeModifier)
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
int64_t GetCurrentTimeSlot()
Definition: timedata.cpp:106
#define strprintf
Definition: tinyformat.h:1056
bool NetworkUpgradeActive(int nHeight, const Consensus::Params &params, Consensus::UpgradeIndex idx)
Returns true if the given network upgrade is active as of the given block height.
Definition: upgrades.cpp:107
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.