uint256 hashInvalidCheckpoint = 0;
CCriticalSection cs_hashSyncCheckpoint;
+ // ppcoin: get last synchronized checkpoint
+ CBlockIndex* GetLastSyncCheckpoint()
+ {
+ CRITICAL_BLOCK(cs_hashSyncCheckpoint)
+ {
+ if (!mapBlockIndex.count(hashSyncCheckpoint))
+ error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
+ else
+ return mapBlockIndex[hashSyncCheckpoint];
+ }
+ return NULL;
+ }
+
// ppcoin: only descendant of current sync-checkpoint is allowed
bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
{
return true;
}
- bool IsPendingSyncCheckpoint(uint256 hashBlock)
+ bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
{
CRITICAL_BLOCK(cs_hashSyncCheckpoint)
- return ((!checkpointMessagePending.IsNull()) && hashBlock == checkpointMessagePending.hashCheckpoint);
+ {
+ if (checkpointMessagePending.IsNull())
+ return false;
+ if (hashBlock == checkpointMessagePending.hashCheckpoint)
+ return true;
+ if (mapOrphanBlocks.count(checkpointMessagePending.hashCheckpoint)
+ && hashBlock == WantedByOrphan(mapOrphanBlocks[checkpointMessagePending.hashCheckpoint]))
+ return true;
+ }
+ return false;
}
// ppcoin: automatic checkpoint (represented by height of checkpoint)
pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
// ask directly as well in case rejected earlier by duplicate
// proof-of-stake because getblocks may not get it this time
- pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? GetOrphanRoot(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
+ pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
}
return false;
}
return true;
}
-uint256 GetOrphanRoot(const CBlock* pblock)
+uint256 static GetOrphanRoot(const CBlock* pblock)
{
// Work back to the first block in the orphan chain
while (mapOrphanBlocks.count(pblock->hashPrevBlock))
return pblock->GetHash();
}
+// ppcoin: find block wanted by given orphan block
+uint256 WantedByOrphan(const CBlock* pblockOrphan)
+{
+ // Work back to the first block in the orphan chain
+ while (mapOrphanBlocks.count(pblockOrphan->hashPrevBlock))
+ pblockOrphan = mapOrphanBlocks[pblockOrphan->hashPrevBlock];
+ return pblockOrphan->hashPrevBlock;
+}
+
int64 static GetProofOfWorkReward(unsigned int nBits)
{
CBigNum bnSubsidyLimit = 9999 * COIN; // subsidy amount for difficulty 1
{
CBigNum bnResult;
bnResult.SetCompact(nBase);
+ bnResult *= 2;
while (nTime > 0 && bnResult < bnProofOfWorkLimit)
{
- // Maximum 400% adjustment...
- bnResult *= 4;
- // ... in best-case exactly 4-times-normal target time
- nTime -= nTargetTimespan*4;
+ // Maximum 200% adjustment per day...
+ bnResult *= 2;
+ nTime -= 24 * 60 * 60;
}
if (bnResult > bnProofOfWorkLimit)
bnResult = bnProofOfWorkLimit;
// ppcoin: check proof-of-stake
// Limited duplicity on stake: prevents block flood attack
// Duplicate stake allowed only when there is orphan child block
- if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::IsPendingSyncCheckpoint(hash))
+ if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str());
// Preliminary checks
if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits))
return error("ProcessBlock() : check proof-of-stake failed for block %s", hash.ToString().c_str());
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(mapBlockIndex);
- if (pcheckpoint && pblock->hashPrevBlock != hashBestChain)
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
+ if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
{
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
- if (deltaTime < 0)
- {
- pfrom->Misbehaving(100);
- return error("ProcessBlock() : block with timestamp before last checkpoint");
- }
CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits);
CBigNum bnRequired;
- if (pblock->IsProofOfWork())
- bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
- else
- bnRequired = bnNewBlock; // TODO: Computer Min Stake Target Allowed
+ bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime));
if (bnNewBlock > bnRequired)
{
{
// Limited duplicity on stake: prevents block flood attack
// Duplicate stake allowed only when there is orphan child block
- if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::IsPendingSyncCheckpoint(hash))
+ if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for orphan block %s", pblock2->GetProofOfStake().first.ToString().c_str(), pblock2->GetProofOfStake().second, hash.ToString().c_str());
else
setStakeSeenOrphan.insert(pblock2->GetProofOfStake());
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
// ppcoin: getblocks may not obtain the ancestor block rejected
// earlier by duplicate-stake check so we ask for it again directly
- pfrom->AskFor(CInv(MSG_BLOCK, GetOrphanRoot(pblock2)));
+ pfrom->AskFor(CInv(MSG_BLOCK, WantedByOrphan(pblock2)));
}
return true;
}