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;
}
if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
return error("Reorganize() : WriteHashBestChain failed");
- if (!txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint)))
- return error("Reorganize() : WriteAutoCheckpoint failed");
// Make sure it's successfully written to disk before changing memory structure
if (!txdb.TxnCommit())
if (pindexGenesisBlock == NULL && hash == hashGenesisBlock)
{
txdb.WriteHashBestChain(hash);
- txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint));
if (!txdb.TxnCommit())
return error("SetBestChain() : TxnCommit failed");
pindexGenesisBlock = pindexNew;
else if (hashPrevBlock == hashBestChain)
{
// Adding to current best branch
- if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash) || !txdb.WriteAutoCheckpoint(Checkpoints::GetNextAutoCheckpoint(pindexNew->nCheckpoint)))
+ if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
{
txdb.TxnAbort();
InvalidChainFound(pindexNew);
nBestChainTrust = pindexNew->nChainTrust;
nTimeBestReceived = GetTime();
nTransactionsUpdated++;
- Checkpoints::AdvanceAutoCheckpoint(pindexBest->nCheckpoint);
printf("SetBestChain: new best=%s height=%d trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str());
return true;
{
pindexNew->pprev = (*miPrev).second;
pindexNew->nHeight = pindexNew->pprev->nHeight + 1;
-
- // ppcoin: compute chain checkpoint
- pindexNew->nCheckpoint = Checkpoints::GetNextChainCheckpoint(pindexNew->pprev);
- assert (pindexNew->nCheckpoint >= pindexNew->pprev->nCheckpoint);
}
// ppcoin: compute chain trust score
if (!Checkpoints::CheckHardened(nHeight, hash))
return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lockin at %d", nHeight));
- // ppcoin: check that the block satisfies automatic checkpoint
- if (!Checkpoints::CheckAuto(pindexPrev))
- return DoS(100, error("AcceptBlock() : rejected by automatic checkpoint at %d", Checkpoints::nAutoCheckpoint));
-
// ppcoin: check that the block satisfies synchronized checkpoint
if (!Checkpoints::CheckSync(hash, pindexPrev))
return error("AcceptBlock() : rejected by synchronized checkpoint");
// 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))
+ 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))
+ 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());
// Ask this guy to fill in what we're missing
if (pfrom)
+ {
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, WantedByOrphan(pblock2)));
+ }
return true;
}
return error("LoadBlockIndex() : genesis block not accepted");
// ppcoin: initialize synchronized checkpoint
- CTxDB txdbc;
- if (!txdbc.WriteSyncCheckpoint(hashGenesisBlock))
+ if (!Checkpoints::WriteSyncCheckpoint(hashGenesisBlock))
return error("LoadBlockIndex() : failed to init sync checkpoint");
- txdbc.Close();
- Checkpoints::hashSyncCheckpoint = hashGenesisBlock;
+ }
+
+ // ppcoin: if checkpoint master key changed must reset sync-checkpoint
+ {
+ CTxDB txdb;
+ string strPubKey = "";
+ if (!txdb.ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey)
+ {
+ // write checkpoint master key to db
+ txdb.TxnBegin();
+ if (!txdb.WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey))
+ return error("LoadBlockIndex() : failed to write new checkpoint master key to db");
+ if (!txdb.TxnCommit())
+ return error("LoadBlockIndex() : failed to commit new checkpoint master key to db");
+ if (!Checkpoints::ResetSyncCheckpoint())
+ return error("LoadBlockIndex() : failed to reset sync-checkpoint");
+ }
+ txdb.Close();
}
return true;
strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.";
}
+ if (Checkpoints::hashInvalidCheckpoint != 0)
+ {
+ nPriority = 3000;
+ strStatusBar = strRPC = "WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.";
+ }
+
// Alerts
CRITICAL_BLOCK(cs_mapAlerts)
{
};
-CBlock* CreateNewBlock(CWallet* pwallet)
+CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfWorkOnly)
{
CReserveKey reservekey(pwallet);
// ppcoin: if coinstake available add coinstake tx
static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift + 60; // only initialized at startup
CBlockIndex* pindexPrev = pindexBest;
- while (nLastCoinStakeCheckTime < GetAdjustedTime())
+
+ if (!fProofOfWorkOnly)
{
- pindexPrev = pindexBest; // get best block again to avoid getting stale
- pblock->nBits = GetNextTargetRequired(pindexPrev, true);
- static CCriticalSection cs;
- CTransaction txCoinStake;
- CRITICAL_BLOCK(cs)
- {
- // mining may have been suspended for a while so
- // need to take max to satisfy the timestamp protocol
- nLastCoinStakeCheckTime = max(++nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60));
- txCoinStake.nTime = nLastCoinStakeCheckTime;
- }
- if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake))
+ while (nLastCoinStakeCheckTime < GetAdjustedTime())
{
- pblock->vtx.push_back(txCoinStake);
- pblock->vtx[0].vout[0].SetEmpty();
- break;
+ pindexPrev = pindexBest; // get best block again to avoid getting stale
+ pblock->nBits = GetNextTargetRequired(pindexPrev, true);
+ static CCriticalSection cs;
+ CTransaction txCoinStake;
+ CRITICAL_BLOCK(cs)
+ {
+ // mining may have been suspended for a while so
+ // need to take max to satisfy the timestamp protocol
+ nLastCoinStakeCheckTime = max(++nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift + 60));
+ txCoinStake.nTime = nLastCoinStakeCheckTime;
+ }
+ if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake))
+ {
+ pblock->vtx.push_back(txCoinStake);
+ pblock->vtx[0].vout[0].SetEmpty();
+ break;
+ }
}
}
// ppcoin: if proof-of-stake block found then process block
if (pblock->IsProofOfStake())
{
- // should be able to sign block - assert here for now
- assert(pblock->SignBlock(*pwalletMain));
+ if (!pblock->SignBlock(*pwalletMain))
+ {
+ error("BitcoinMiner: Unable to sign new proof-of-stake block");
+ return;
+ }
printf("BitcoinMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CheckWork(pblock.get(), *pwalletMain, reservekey);
// Found a solution
pblock->nNonce = ByteReverse(nNonceFound);
assert(hash == pblock->GetHash());
- // should be able to sign block - assert here for now
- assert(pblock->SignBlock(*pwalletMain));
+ if (!pblock->SignBlock(*pwalletMain))
+ {
+ error("BitcoinMiner: Unable to sign new proof-of-work block");
+ return;
+ }
SetThreadPriority(THREAD_PRIORITY_NORMAL);
CheckWork(pblock.get(), *pwalletMain, reservekey);