@@ -60,18 +60,18 @@ static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64& nStakeModifi
6060}
6161
6262// Get selection interval section (in seconds)
63- static int64 GetStakeModifierSelectionIntervalSection (int nSection)
63+ static int64 GetStakeModifierSelectionIntervalSection (int nSection, uint nActualModifierInterval )
6464{
6565 assert (nSection >= 0 && nSection < 64 );
66- return (nModifierInterval * 63 / (63 + ((63 - nSection) * (MODIFIER_INTERVAL_RATIO - 1 ))));
66+ return (nActualModifierInterval * 63 / (63 + ((63 - nSection) * (MODIFIER_INTERVAL_RATIO - 1 ))));
6767}
6868
6969// Get stake modifier selection interval (in seconds)
70- static int64 GetStakeModifierSelectionInterval ()
70+ static int64 GetStakeModifierSelectionInterval (uint nActualModifierInterval )
7171{
7272 int64 nSelectionInterval = 0 ;
7373 for (int nSection=0 ; nSection<64 ; nSection++)
74- nSelectionInterval += GetStakeModifierSelectionIntervalSection (nSection);
74+ nSelectionInterval += GetStakeModifierSelectionIntervalSection (nSection, nActualModifierInterval );
7575 return nSelectionInterval;
7676}
7777
@@ -152,14 +152,23 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif
152152 {
153153 printf (" ComputeNextStakeModifier: prev modifier=0x%016" PRI64x" time=%s\n " , nStakeModifier, DateTimeStrFormat (nModifierTime).c_str ());
154154 }
155- if (nModifierTime / nModifierInterval >= pindexPrev->GetBlockTime () / nModifierInterval)
156- return true ;
155+
156+ uint nActualModifierInterval;
157+ if ((fTestNet && (pindexPrev->nHeight > TESTNET_HFORK5_HEIGHT)) ||
158+ (!fTestNet && (pindexPrev->nHeight > HFORK5_HEIGHT)))
159+ nActualModifierInterval = nModifierIntervalNew;
160+ else
161+ nActualModifierInterval = nModifierInterval;
162+
163+ if ((nModifierTime / nActualModifierInterval) >= (pindexPrev->GetBlockTime () / nActualModifierInterval))
164+ return (true );
157165
158166 // Sort candidate blocks by timestamp
159167 vector<pair<int64, uint256> > vSortedByTimestamp;
160- vSortedByTimestamp.reserve (64 * nModifierInterval / nBaseTargetSpacing);
161- int64 nSelectionInterval = GetStakeModifierSelectionInterval ();
162- int64 nSelectionIntervalStart = (pindexPrev->GetBlockTime () / nModifierInterval) * nModifierInterval - nSelectionInterval;
168+ vSortedByTimestamp.reserve (64 * nActualModifierInterval / nBaseTargetSpacing);
169+ int64 nSelectionInterval = GetStakeModifierSelectionInterval (nActualModifierInterval);
170+ int64 nSelectionIntervalStart =
171+ (pindexPrev->GetBlockTime () / nActualModifierInterval) * nActualModifierInterval - nSelectionInterval;
163172 const CBlockIndex* pindex = pindexPrev;
164173 while (pindex && pindex->GetBlockTime () >= nSelectionIntervalStart)
165174 {
@@ -177,7 +186,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif
177186 for (int nRound=0 ; nRound<min (64 , (int )vSortedByTimestamp.size ()); nRound++)
178187 {
179188 // add an interval section to the current selection round
180- nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection (nRound);
189+ nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection (nRound, nActualModifierInterval );
181190 // select a block from the candidates of current round
182191 if (!SelectBlockFromCandidates (vSortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, &pindex))
183192 return error (" ComputeNextStakeModifier: unable to select block at round %d" , nRound);
@@ -231,7 +240,15 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier
231240 const CBlockIndex* pindexFrom = mapBlockIndex[hashBlockFrom];
232241 nStakeModifierHeight = pindexFrom->nHeight ;
233242 nStakeModifierTime = pindexFrom->GetBlockTime ();
234- int64 nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval ();
243+
244+ uint nActualModifierInterval;
245+ if ((fTestNet && (pindexFrom->nHeight > TESTNET_HFORK5_HEIGHT)) ||
246+ (!fTestNet && (pindexFrom->nHeight > HFORK5_HEIGHT)))
247+ nActualModifierInterval = nModifierIntervalNew;
248+ else
249+ nActualModifierInterval = nModifierInterval;
250+
251+ int64 nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval (nActualModifierInterval);
235252 const CBlockIndex* pindex = pindexFrom;
236253 // loop to find the stake modifier later by a selection interval
237254 while (nStakeModifierTime < pindexFrom->GetBlockTime () + nStakeModifierSelectionInterval)
@@ -276,20 +293,16 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier
276293// quantities so as to generate blocks faster, degrading the system back into
277294// a proof-of-work situation.
278295//
279- bool CheckStakeKernelHash (unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool & fFatal , bool fMiner , bool fPrintProofOfStake )
280- {
281- if (nTimeTx < txPrev.nTime ) // Transaction timestamp violation
282- {
283- fFatal = true ;
284- return error (" CheckStakeKernelHash() : nTime violation" );
285- }
296+ bool CheckStakeKernelHash (unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset,
297+ const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake,
298+ uint256& targetProofOfStake, bool & fCritical , bool fMiner , bool fPrintProofOfStake ) {
299+
300+ if (nTimeTx < txPrev.nTime )
301+ return (error (" CheckStakeKernelHash() : time stamp violation" ));
286302
287303 unsigned int nTimeBlockFrom = blockFrom.GetBlockTime ();
288- if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement
289- {
290- fFatal = true ;
291- return error (" CheckStakeKernelHash() : min age violation" );
292- }
304+ if (nTimeBlockFrom + nStakeMinAge > nTimeTx)
305+ return (error (" CheckStakeKernelHash() : min. age violation" ));
293306
294307 CBigNum bnTargetPerCoinDay;
295308 bnTargetPerCoinDay.SetCompact (nBits);
@@ -306,8 +319,12 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
306319 int nStakeModifierHeight = 0 ;
307320 int64 nStakeModifierTime = 0 ;
308321
309- if (!GetKernelStakeModifier (hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake ))
310- return false ;
322+ if (!GetKernelStakeModifier (hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime,
323+ fPrintProofOfStake )) {
324+ fCritical = false ;
325+ return (false );
326+ }
327+
311328 ss << nStakeModifier;
312329
313330 ss << nTimeBlockFrom << nTxPrevOffset << txPrev.nTime << prevout.n << nTimeTx;
@@ -327,10 +344,10 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
327344 }
328345
329346 // Now check if proof-of-stake hash meets target protocol
330- if (CBigNum (hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
331- {
332- fFatal = true ;
333- return ! fMiner ? error ( " CheckStakeKernelHash() : proof-of-stake not meeting target " ) : false ;
347+ if (CBigNum (hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay) {
348+ /* Stake miner produces floods of these */
349+ if (! fMiner ) return ( error ( " CheckStakeKernelHash() : proof-of-stake not meeting target " )) ;
350+ return ( false ) ;
334351 }
335352
336353 if (fDebug && !fPrintProofOfStake )
@@ -345,17 +362,16 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
345362 nTimeBlockFrom, nTxPrevOffset, txPrev.nTime , prevout.n , nTimeTx,
346363 hashProofOfStake.ToString ().c_str ());
347364 }
348- return true ;
365+
366+ return (true );
349367}
350368
351369// Check kernel hash target and coinstake signature
352- bool CheckProofOfStake (const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake, bool & fFatal , bool fMiner )
353- {
354- if (!tx.IsCoinStake ())
355- {
356- fFatal = true ;
357- return error (" CheckProofOfStake() : called on non-coinstake %s" , tx.GetHash ().ToString ().c_str ());
358- }
370+ bool CheckProofOfStake (const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake,
371+ uint256& targetProofOfStake, bool & fCritical , bool fMiner ) {
372+
373+ if (!tx.IsCoinStake ())
374+ return (error (" CheckProofOfStake() : %s not a coin stake" , tx.GetHash ().ToString ().c_str ()));
359375
360376 // Kernel (input 0) must match the stake hash target per coin age (nBits)
361377 const CTxIn& txin = tx.vin [0 ];
@@ -365,8 +381,12 @@ bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hash
365381 CCoins coins;
366382 CCoinsViewCache &view = *pcoinsTip;
367383
368- if (!view.GetCoinsReadOnly (txin.prevout .hash , coins))
369- return fDebug ? error (" CheckProofOfStake() : INFO: read coins for txPrev failed" ) : false ; // previous transaction not in main chain, may occur during initial download
384+ /* May happen if the previous transaction isn't in the main chain yet */
385+ if (!view.GetCoinsReadOnly (txin.prevout .hash , coins)) {
386+ fCritical = false ;
387+ if (fDebug ) return (error (" CheckProofOfStake() : cannot find a previous transaction output" ));
388+ return (false );
389+ }
370390
371391 CBlockIndex* pindex = FindBlockByHeight (coins.nHeight );
372392
@@ -382,34 +402,33 @@ bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hash
382402 nTxPos += tx.GetSerializeSize (SER_DISK, CLIENT_VERSION);
383403 }
384404 }
385- else
386- return fDebug ? error (" CheckProofOfStake() : read block failed" ) : false ; // unable to read block of previous transaction
405+ else {
406+ /* May happen if the block isn't in the main chain yet */
407+ fCritical = false ;
408+ if (fDebug ) return (error (" CheckProofOfStake() : cannot load a block requested" ));
409+ return (false );
410+ }
387411
388412 const CTxOut& txout = txPrev.vout [txin.prevout .n ];
389413
390414 // Check transaction consistency
391- if (txin.prevout .n >= txPrev.vout .size ())
392- {
393- fFatal = true ;
394- return error (" CheckProofOfStake() : invalid prevout found in coinstake %s" , tx.GetHash ().ToString ().c_str ());
395- }
415+ if (txin.prevout .n >= txPrev.vout .size ())
416+ return (error (" CheckProofOfStake() : coin stake %s with an invalid input" ,
417+ tx.GetHash ().ToString ().c_str ()));
396418
397419 // Verify script
398- if (!VerifyScript (txin.scriptSig , txout.scriptPubKey , tx, 0 , true , false , 0 ))
399- {
400- fFatal = true ;
401- return error (" CheckProofOfStake() : VerifyScript failed on coinstake %s" , tx.GetHash ().ToString ().c_str ());
420+ if (!VerifyScript (txin.scriptSig , txout.scriptPubKey , tx, 0 , true , false , 0 ))
421+ return (error (" CheckProofOfStake() : coin stake %s script verification failed" ,
422+ tx.GetHash ().ToString ().c_str ()));
423+
424+ if (!CheckStakeKernelHash (nBits, block, nTxPos, txPrev, txin.prevout , tx.nTime ,
425+ hashProofOfStake, targetProofOfStake, fCritical , fMiner , fDebug )) {
426+ if (fDebug ) return (error (" CheckProofOfStake() : kernel check failed on coin stake %s, proof=%s" ,
427+ tx.GetHash ().ToString ().c_str (), hashProofOfStake.ToString ().c_str ()));
428+ return (false );
402429 }
403430
404- if (!CheckStakeKernelHash (nBits, block, nTxPos, txPrev, txin.prevout , tx.nTime , hashProofOfStake, targetProofOfStake, fFatal , fMiner , fDebug ))
405- {
406- if (fFatal )
407- return false ;
408- // may occur during initial download or if behind on block chain sync
409- return fDebug ? error (" CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s" , tx.GetHash ().ToString ().c_str (), hashProofOfStake.ToString ().c_str ()) : false ;
410- }
411-
412- return true ;
431+ return (true );
413432}
414433
415434// Check whether the coinstake timestamp meets protocol
0 commit comments