map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
+set<COutPoint> setStakeSeenOrphan;
map<uint256, CDataStream*> mapOrphanTransactions;
multimap<uint256, CDataStream*> mapOrphanTransactionsByPrev;
// ppcoin: coinstake must meet hash target according to the protocol:
-// at least one input must meet the formula
+// input 0 must meet the formula
// hash(nBits + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDay
// this ensures that the chance of getting a coinstake is proportional to the
// amount of coin age one owns.
if (!pindexNew)
return error("AddToBlockIndex() : new CBlockIndex failed");
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ if (pindexNew->fProofOfStake)
+ setStakeSeen.insert(pindexNew->prevoutStake);
pindexNew->phashBlock = &((*mi).first);
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,20).c_str());
+ // ppcoin: check proof-of-stake
+ if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()))
+ return error("ProcessBlock() : duplicate proof-of-stake (%s) for block %s", pblock->GetProofOfStake().ToString().c_str(), hash.ToString().c_str());
+
// Preliminary checks
if (!pblock->CheckBlock())
return error("ProcessBlock() : CheckBlock FAILED");
{
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
CBlock* pblock2 = new CBlock(*pblock);
+ // ppcoin: check proof-of-stake
+ if (pblock2->IsProofOfStake())
+ {
+ if (setStakeSeenOrphan.count(pblock2->GetProofOfStake()))
+ return error("ProcessBlock() : duplicate proof-of-stake (%s) for orphan block %s", pblock2->GetProofOfStake().ToString().c_str(), hash.ToString().c_str());
+ else
+ setStakeSeenOrphan.insert(pblock2->GetProofOfStake());
+ }
mapOrphanBlocks.insert(make_pair(hash, pblock2));
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
if (pblockOrphan->AcceptBlock())
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
+ setStakeSeenOrphan.erase(pblockOrphan->GetProofOfStake());
delete pblockOrphan;
}
mapOrphanBlocksByPrev.erase(hashPrev);
return !IsProofOfStake();
}
+ COutPoint GetProofOfStake() const
+ {
+ return IsProofOfStake()? vtx[1].vin[0].prevout : COutPoint();
+ }
+
// ppcoin: get max transaction timestamp
int64 GetMaxTransactionTime() const
{
std::string ToString() const
{
- return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nChainTrust=%"PRI64d" nHeight=%d, nCheckpoint=%d, fProofOfStake=%d merkle=%s, hashBlock=%s)",
- pprev, pnext, nFile, nBlockPos, nChainTrust, nHeight, nCheckpoint, fProofOfStake,
+ return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nChainTrust=%"PRI64d" nHeight=%d, nCheckpoint=%d, fProofOfStake=%d prevoutStake=(%s) merkle=%s, hashBlock=%s)",
+ pprev, pnext, nFile, nBlockPos, nChainTrust, nHeight, nCheckpoint,
+ fProofOfStake, prevoutStake.ToString().c_str(),
hashMerkleRoot.ToString().substr(0,10).c_str(),
GetBlockHash().ToString().substr(0,20).c_str());
}