@@ -101,14 +101,14 @@ static bool SelectBlockFromCandidates(
101
101
continue ;
102
102
// compute the selection hash by hashing its proof-hash and the
103
103
// previous proof-of-stake modifier
104
- uint256 hashProof = pindex->IsProofOfStake () ? pindex->hashProofOfStake : pindex->GetBlockHash ();
104
+ uint256 hashProof = pindex->IsProofOfStake (false ) ? pindex->hashProofOfStake : pindex->GetBlockHash ();
105
105
CDataStream ss (SER_GETHASH, 0 );
106
106
ss << hashProof << nStakeModifierPrev;
107
107
arith_uint256 hashSelection = UintToArith256 (Hash (ss.begin (), ss.end ()));
108
108
// the selection hash is divided by 2**32 so that proof-of-stake block
109
109
// is always favored over proof-of-work block. this is to preserve
110
110
// the energy efficiency property
111
- if (pindex->IsProofOfStake ())
111
+ if (pindex->IsProofOfStake (false ))
112
112
hashSelection >>= 32 ;
113
113
if (fSelected && hashSelection < hashBest)
114
114
{
@@ -127,6 +127,22 @@ static bool SelectBlockFromCandidates(
127
127
return fSelected ;
128
128
}
129
129
130
+ // Stake Modifier (hash modifier of proof-of-stake):
131
+ // The purpose of stake modifier is to prevent a txout (coin) owner from
132
+ // computing future proof-of-stake generated by this txout at the time
133
+ // of transaction confirmation. To meet kernel protocol, the txout
134
+ // must hash with a future stake modifier to generate the proof.
135
+ uint256 ComputeStakeModifierV3 (const CBlockIndex* pindexPrev, const uint256& kernel)
136
+ {
137
+ if (!pindexPrev)
138
+ return uint256 (); // genesis block's modifier is 0
139
+
140
+ CDataStream ss (SER_GETHASH, 0 );
141
+ ss << kernel << pindexPrev->hashStakeModifierV3 ;
142
+ return Hash (ss.begin (), ss.end ());
143
+ }
144
+
145
+
130
146
// Stake Modifier (hash modifier of proof-of-stake):
131
147
// The purpose of stake modifier is to prevent a txout (coin) owner from
132
148
// computing future proof-of-stake generated by this txout at the time
@@ -217,15 +233,15 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t& nStake
217
233
while (pindex && pindex->nHeight >= nHeightFirstCandidate)
218
234
{
219
235
// '=' indicates proof-of-stake blocks not selected
220
- if (pindex->IsProofOfStake ())
236
+ if (pindex->IsProofOfStake (false ))
221
237
strSelectionMap.replace (pindex->nHeight - nHeightFirstCandidate, 1 , " =" );
222
238
pindex = pindex->pprev ;
223
239
}
224
240
for (const auto & item : mapSelectedBlocks)
225
241
{
226
242
// 'S' indicates selected proof-of-stake blocks
227
243
// 'W' indicates selected proof-of-work blocks
228
- strSelectionMap.replace (item.second ->nHeight - nHeightFirstCandidate, 1 , item.second ->IsProofOfStake () ? " S" : " W" );
244
+ strSelectionMap.replace (item.second ->nHeight - nHeightFirstCandidate, 1 , item.second ->IsProofOfStake (false ) ? " S" : " W" );
229
245
}
230
246
LogPrint (BCLog::KERNEL, " %s : selection height [%d, %d] map %s\n " , __func__, nHeightFirstCandidate, pindexPrev->nHeight , strSelectionMap.c_str ());
231
247
}
@@ -368,16 +384,18 @@ uint256 stakeHash(unsigned int nTimeTx, CDataStream ss, unsigned int prevoutInde
368
384
// quantities so as to generate blocks faster, degrading the system back into
369
385
// a proof-of-work situation.
370
386
//
371
- bool CheckStakeKernelHash (unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake )
387
+ bool CheckStakeKernelHash (const CBlockIndex* pindexPrev, unsigned int nBits, uint256 hashBlockFrom, int64_t blockFromTime,
388
+ const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx,
389
+ uint256& hashProofOfStake, bool fPoSV3 , bool fPrintProofOfStake )
372
390
{
373
- nTxPrevOffset = 336 ;
374
- auto txPrevTime = blockFrom.GetBlockTime ();
391
+ auto nTxPrevOffset = 336 ;
392
+ auto txPrevTime = blockFromTime;
393
+ unsigned int nTimeBlockFrom = blockFromTime;
375
394
if (nTimeTx < txPrevTime) // Transaction timestamp violation
376
395
return error (" CheckStakeKernelHash() : nTime violation" );
377
396
378
397
auto nStakeMinAge = Params ().GetConsensus ().nStakeMinAge ;
379
398
auto nStakeMaxAge = Params ().GetConsensus ().nStakeMaxAge ;
380
- unsigned int nTimeBlockFrom = blockFrom.GetBlockTime ();
381
399
if (nTimeBlockFrom + nStakeMinAge > nTimeTx) // Min age requirement
382
400
return error (" CheckStakeKernelHash() : min age violation" );
383
401
@@ -396,10 +414,16 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
396
414
int nStakeModifierHeight = 0 ;
397
415
int64_t nStakeModifierTime = 0 ;
398
416
399
- if (!GetKernelStakeModifier (blockFrom.GetHash (), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake ))
400
- return error (" Failed to get kernel stake modifier" );
417
+ if (fPoSV3 ) {
418
+ ss << pindexPrev->hashStakeModifierV3 ;
419
+ }
420
+ else {
421
+
422
+ if (!GetKernelStakeModifier (hashBlockFrom, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake ))
423
+ return error (" Failed to get kernel stake modifier" );
401
424
402
- ss << nStakeModifier;
425
+ ss << nStakeModifier;
426
+ }
403
427
404
428
ss << nTimeBlockFrom << nTxPrevOffset << txPrevTime << prevout.n << nTimeTx;
405
429
hashProofOfStake = Hash (ss.begin (), ss.end ());
@@ -409,14 +433,14 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
409
433
__func__,
410
434
nStakeModifier, nStakeModifierHeight,
411
435
DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , nStakeModifierTime).c_str (),
412
- mapBlockIndex[blockFrom. GetHash () ]->nHeight ,
413
- DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , blockFrom. GetBlockTime () ).c_str ());
436
+ mapBlockIndex[hashBlockFrom ]->nHeight ,
437
+ DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , blockFromTime ).c_str ());
414
438
415
439
LogPrint (BCLog::KERNEL, " %s : check protocol=%s modifier=0x%016" PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n " ,
416
440
__func__,
417
441
" 0.5" ,
418
442
nStakeModifier,
419
- nTimeBlockFrom , nTxPrevOffset,
443
+ blockFromTime , nTxPrevOffset,
420
444
txPrevTime, prevout.n , nTimeTx,
421
445
hashProofOfStake.ToString ().c_str ());
422
446
}
@@ -431,13 +455,14 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned
431
455
__func__,
432
456
nStakeModifier, nStakeModifierHeight,
433
457
DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , nStakeModifierTime).c_str (),
434
- mapBlockIndex[blockFrom.GetHash ()]->nHeight ,
435
- DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , blockFrom.GetBlockTime ()).c_str ());
458
+ mapBlockIndex[hashBlockFrom]->nHeight ,
459
+ DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , blockFromTime).c_str ());
460
+
436
461
LogPrint (BCLog::KERNEL, " %s : Generated pass protocol=%s modifier=0x%016" PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n " ,
437
462
__func__,
438
463
" 0.5" ,
439
464
nStakeModifier,
440
- nTimeBlockFrom , nTxPrevOffset, txPrevTime, prevout.n , nTimeTx,
465
+ blockFromTime , nTxPrevOffset, txPrevTime, prevout.n , nTimeTx,
441
466
hashProofOfStake.ToString ().c_str ());
442
467
}
443
468
return true ;
@@ -470,7 +495,7 @@ bool CheckKernelScript(CScript scriptVin, CScript scriptVout)
470
495
}
471
496
472
497
// Check kernel hash target and coinstake signature
473
- bool CheckProofOfStake (const CBlock &block, uint256& hashProofOfStake)
498
+ bool CheckProofOfStake (const CBlockIndex *pindexPrev, const CBlock &block, uint256& hashProofOfStake, const Consensus::Params ¶ms )
474
499
{
475
500
const CTransactionRef &tx = block.vtx [1 ];
476
501
if (!tx->IsCoinStake ())
@@ -483,9 +508,7 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
483
508
uint256 hashBlock;
484
509
CTransactionRef txPrev;
485
510
486
- const auto &cons = Params ().GetConsensus ();
487
-
488
- if (!GetTransaction (txin.prevout .hash , txPrev, cons, hashBlock, true ))
511
+ if (!GetTransaction (txin.prevout .hash , txPrev, params, hashBlock, true ))
489
512
return error (" CheckProofOfStake() : INFO: read txPrev failed" );
490
513
491
514
CTxOut prevTxOut = txPrev->vout [txin.prevout .n ];
@@ -498,7 +521,7 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
498
521
return error (" CheckProofOfStake() : VerifySignature failed on coinstake %s" , tx->GetHash ().ToString ().c_str ());
499
522
}
500
523
501
- CBlockIndex* pindex = NULL ;
524
+ CBlockIndex* pindex = nullptr ;
502
525
BlockMap::iterator it = mapBlockIndex.find (hashBlock);
503
526
if (it != mapBlockIndex.end ())
504
527
pindex = it->second ;
@@ -507,14 +530,16 @@ bool CheckProofOfStake(const CBlock &block, uint256& hashProofOfStake)
507
530
508
531
// Read block header
509
532
CBlock blockprev;
510
- if (!ReadBlockFromDisk (blockprev, pindex->GetBlockPos (), cons ))
533
+ if (!ReadBlockFromDisk (blockprev, pindex->GetBlockPos (), params ))
511
534
return error (" CheckProofOfStake(): INFO: failed to find block" );
512
535
513
536
if (!CheckKernelScript (prevTxOut.scriptPubKey , tx->vout [1 ].scriptPubKey ))
514
537
return error (" CheckProofOfStake() : INFO: check kernel script failed on coinstake %s, hashProof=%s \n " , tx->GetHash ().ToString ().c_str (), hashProofOfStake.ToString ().c_str ());
515
538
539
+ bool isProofOfStakeV3 = params.nPoSUpdgradeHFHeight < pindexPrev->nHeight ;
540
+
516
541
unsigned int nTime = block.nTime ;
517
- if (!CheckStakeKernelHash (block.nBits , blockprev, /* postx->nTxOffset + */ sizeof (CBlock ), txPrev, txin.prevout , nTime, hashProofOfStake, true ))
542
+ if (!CheckStakeKernelHash (pindexPrev, block.nBits , blockprev. GetHash (), blockprev. GetBlockTime ( ), txPrev, txin.prevout , nTime, hashProofOfStake, isProofOfStakeV3 , true ))
518
543
return error (" CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s \n " , tx->GetHash ().ToString ().c_str (), hashProofOfStake.ToString ().c_str ()); // may occur during initial download or if behind on block chain sync
519
544
520
545
return true ;
@@ -547,3 +572,4 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck
547
572
return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
548
573
return true ;
549
574
}
575
+
0 commit comments