8 #include <boost/assign/list_of.hpp>
27 return MODIFIER_INTERVAL_TESTNET;
29 return MODIFIER_INTERVAL;
33 static std::map<int, unsigned int> mapStakeModifierCheckpoints =
34 boost::assign::map_list_of(0, 0xfd11f4e7u);
37 int64_t
GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd)
43 static bool GetLastStakeModifier(
const CBlockIndex* pindex, uint64_t& nStakeModifier, int64_t& nModifierTime)
46 return error(
"%s : null pindex", __func__);
48 pindex = pindex->
pprev;
50 return error(
"%s : no generation at genesis block", __func__);
57 static int64_t GetStakeModifierSelectionIntervalSection(
int nSection)
59 assert(nSection >= 0 && nSection < 64);
65 static int64_t GetStakeModifierSelectionInterval()
67 int64_t nSelectionInterval = 0;
68 for (
int nSection = 0; nSection < 64; nSection++) {
69 nSelectionInterval += GetStakeModifierSelectionIntervalSection(nSection);
71 return nSelectionInterval;
77 static bool SelectBlockFromCandidates(
78 std::vector<std::pair<int64_t, uint256> >& vSortedByTimestamp,
79 std::map<uint256, const CBlockIndex*>& mapSelectedBlocks,
80 int64_t nSelectionIntervalStop,
81 uint64_t nStakeModifierPrev,
84 bool fModifierV2 =
false;
85 bool fFirstRun =
true;
86 bool fSelected =
false;
91 return error(
"%s : failed to find block index for candidate block %s", __func__, item.second.ToString().c_str());
94 if (fSelected && pindex->
GetBlockTime() > nSelectionIntervalStop)
103 if (mapSelectedBlocks.count(pindex->
GetBlockHash()) > 0)
114 ss << hashProof << nStakeModifierPrev;
115 uint256 hashSelection =
Hash(ss.begin(), ss.end());
121 hashSelection >>= 32;
123 if (fSelected && hashSelection < hashBest) {
124 hashBest = hashSelection;
126 }
else if (!fSelected) {
128 hashBest = hashSelection;
153 fGeneratedStakeModifier =
false;
155 fGeneratedStakeModifier =
true;
158 if (pindexPrev->
nHeight == 0) {
160 fGeneratedStakeModifier =
true;
161 nStakeModifier = uint64_t(
"stakemodifier");
167 int64_t nModifierTime = 0;
168 if (!GetLastStakeModifier(pindexPrev, nStakeModifier, nModifierTime))
169 return error(
"%s : unable to get last modifier", __func__);
172 LogPrintf(
"%s : prev modifier= %s time=%s\n", __func__, std::to_string(nStakeModifier).c_str(),
DateTimeStrFormat(
"%Y-%m-%d %H:%M:%S", nModifierTime).c_str());
178 std::vector<std::pair<int64_t, uint256> > vSortedByTimestamp;
180 int64_t nSelectionInterval = GetStakeModifierSelectionInterval();
184 while (pindex && pindex->
GetBlockTime() >= nSelectionIntervalStart) {
186 pindex = pindex->
pprev;
189 int nHeightFirstCandidate = pindex ? (pindex->
nHeight + 1) : 0;
190 std::reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end());
191 std::sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end());
194 uint64_t nStakeModifierNew = 0;
195 int64_t nSelectionIntervalStop = nSelectionIntervalStart;
196 std::map<uint256, const CBlockIndex*> mapSelectedBlocks;
197 for (
int nRound = 0; nRound < std::min(64, (
int)vSortedByTimestamp.size()); nRound++) {
199 nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound);
202 if (!SelectBlockFromCandidates(vSortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, &pindex))
203 return error(
"%s : unable to select block at round %d", __func__, nRound);
209 mapSelectedBlocks.insert(std::make_pair(pindex->
GetBlockHash(), pindex));
211 LogPrintf(
"%s : selected round %d stop=%s height=%d bit=%d\n", __func__,
216 if (
GetBoolArg(
"-printstakemodifier",
false)) {
217 std::string strSelectionMap =
"";
219 strSelectionMap.insert(0, pindexPrev->
nHeight - nHeightFirstCandidate + 1,
'-');
221 while (pindex && pindex->
nHeight >= nHeightFirstCandidate) {
224 strSelectionMap.replace(pindex->
nHeight - nHeightFirstCandidate, 1,
"=");
225 pindex = pindex->
pprev;
227 for (
const std::pair<const uint256, const CBlockIndex*> &item : mapSelectedBlocks) {
230 strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake() ?
"S" :
"W");
232 LogPrintf(
"%s : selection height [%d, %d] map %s\n", __func__, nHeightFirstCandidate, pindexPrev->
nHeight, strSelectionMap.c_str());
234 if (
GetBoolArg(
"-printstakemodifier",
false)) {
238 nStakeModifier = nStakeModifierNew;
239 fGeneratedStakeModifier =
true;
245 bool GetKernelStakeModifier(
uint256 hashBlockFrom, uint64_t& nStakeModifier,
int& nStakeModifierHeight, int64_t& nStakeModifierTime,
bool fPrintProofOfStake)
249 return error(
"%s : block not indexed", __func__);
251 nStakeModifierHeight = pindexFrom->
nHeight;
254 if (
Params().IsRegTestNet()) {
258 int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
262 while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval) {
265 return error(
"Null pindexNext\n");
271 nStakeModifierHeight = pindex->
nHeight;
286 return hashProofOfStake < (bnCoinDayWeight * bnTargetPerCoinDay);
290 unsigned int nTimeBlockFrom,
unsigned int& nTimeTx,
uint256& hashProofOfStake)
293 ss << nStakeModifier << nTimeBlockFrom << ssUniqueID << nTimeTx;
301 bool Stake(
CStakeInput* stakeInput,
unsigned int nBits,
unsigned int nTimeBlockFrom,
unsigned int& nTimeTx,
uint256& hashProofOfStake)
303 if(!
Params().IsRegTestNet()) {
304 if (nTimeTx < nTimeBlockFrom)
305 return error(
"%s : nTime violation", __func__);
307 if (nTimeBlockFrom +
Params().StakeMinAge() > nTimeTx)
316 uint64_t nStakeModifier = 0;
318 return error(
"%s : failed to get kernel stake modifier", __func__);
320 bool fSuccess =
false;
321 unsigned int nTryTime = 0;
326 for (
int i = 0; i < nHashDrift; i++)
333 nTryTime = nTimeTx + nHashDrift - i;
336 if (!
CheckStake(ssUniqueID, nValueIn, nStakeModifier, bnTargetPerCoinDay, nTimeBlockFrom, nTryTime, hashProofOfStake))
371 return error(
"%s : INFO: read txPrev failed, tx id prev: %s, block id %s",
376 return error(
"%s : VerifySignature failed on coinstake %s", __func__, tx.
GetHash().
ToString().c_str());
380 stake = std::unique_ptr<CStakeInput>(prcyInput);
385 return error(
"%s : Failed to find the block index for stake origin", __func__);
390 return error(
"%s : INFO: failed to find block", __func__);
395 uint64_t nStakeModifier = 0;
396 if (!stake->GetModifier(nStakeModifier))
397 return error(
"%s : failed to get modifier for stake input\n", __func__);
399 unsigned int nBlockFromTime = blockfrom.
nTime;
400 unsigned int nTxTime = block.
nTime;
402 if (!
Params().IsRegTestNet()) {
403 if (nTxTime < nBlockFromTime)
404 return error(
"%s : nTime violation - nBlockFromTime=%d nTimeTx=%d", __func__, nBlockFromTime, nTxTime);
405 if (nBlockFromTime +
Params().StakeMinAge() > nTxTime)
406 return error(
"%s : min age violation - nBlockFromTime=%d nStakeMinAge=%d nTimeTx=%d",
407 __func__, nBlockFromTime,
Params().StakeMinAge(), nTxTime);
410 if (!
CheckStake(stake->GetUniqueness(), nValueIn, nStakeModifier, bnTargetPerCoinDay, nBlockFromTime,
411 nTxTime, hashProofOfStake)) {
412 return error(
"%s : INFO: check kernel failed on coinstake %s, hashProof=%s, GetValue=%d, nValueIn=%d, nValueOut=%d\n",
413 __func__, tx.
GetHash().
GetHex(), hashProofOfStake.
GetHex(), stake->GetValue(), nValueIn, nValueOut);
428 hashChecksum >>= (256 - 32);
436 if (mapStakeModifierCheckpoints.count(nHeight)) {
437 return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];