From a62be7df34bc078f9820831771c8057a6055e5cf Mon Sep 17 00:00:00 2001 From: Sunny King Date: Tue, 1 May 2012 19:50:39 +0100 Subject: [PATCH] PPCoin: New data structure for detection of block spam --- src/db.cpp | 5 +++++ src/main.cpp | 53 +++++++++++++++++++++++++++-------------------------- src/main.h | 10 +++++++++- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/db.cpp b/src/db.cpp index d4dae8d..d85e4a9 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -542,6 +542,7 @@ bool CTxDB::LoadBlockIndex() pindexNew->nHeight = diskindex.nHeight; pindexNew->nCheckpoint = diskindex.nCheckpoint; pindexNew->fProofOfStake = diskindex.fProofOfStake; + pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; @@ -554,6 +555,10 @@ bool CTxDB::LoadBlockIndex() if (!pindexNew->CheckIndex()) return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); + + // ppcoin: build setStakeSeen + if (pindexNew->fProofOfStake) + setStakeSeen.insert(pindexNew->prevoutStake); } else { diff --git a/src/main.cpp b/src/main.cpp index ef401cd..111c2ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ unsigned int nTransactionsUpdated = 0; map mapNextTx; map mapBlockIndex; +set setStakeSeen; uint256 hashGenesisBlock("0x000000006d52486334316794cc38ffeb7ebf35a7ebd661fd39f5f46b0d001575"); static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" @@ -1312,33 +1313,33 @@ bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const if (!IsCoinStake()) return true; - BOOST_FOREACH(const CTxIn& txin, vin) - { - // First try finding the previous transaction in database - CTransaction txPrev; - CTxIndex txindex; - if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) - continue; // previous transaction not in main chain - if (nTime < txPrev.nTime) - return false; // Transaction timestamp violation - - // Read block header - CBlock block; - if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - return false; // unable to read block of previous transaction - if (block.GetBlockTime() + AUTO_CHECKPOINT_TRUST_SPAN > nTime) - continue; // only count coins from at least one week ago + // Input 0 must match the stake hash target per coin age (nBits) + const CTxIn& txin = vin[0]; - int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; - CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60); - // Calculate hash - CDataStream ss(SER_GETHASH, VERSION); - ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime; - if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) - return true; - } + // First try finding the previous transaction in database + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + return false; // previous transaction not in main chain + if (nTime < txPrev.nTime) + return false; // Transaction timestamp violation - return false; + // Read block header + CBlock block; + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + return false; // unable to read block of previous transaction + if (block.GetBlockTime() + AUTO_CHECKPOINT_TRUST_SPAN > nTime) + return false; // only count coins from at least one week ago + + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60); + // Calculate hash + CDataStream ss(SER_GETHASH, VERSION); + ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime; + if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) + return true; + else + return false; } // ppcoin: total coin age spent in transaction, in the unit of coin-days. diff --git a/src/main.h b/src/main.h index 1d8dc96..a7843b5 100644 --- a/src/main.h +++ b/src/main.h @@ -53,6 +53,7 @@ static const int fHaveUPnP = false; extern CCriticalSection cs_main; extern std::map mapBlockIndex; +extern std::set setStakeSeen; extern uint256 hashGenesisBlock; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; @@ -510,7 +511,7 @@ public: bool IsCoinStake() const { // ppcoin: the coin stake transaction is marked with the first output empty - return (vout.size() == 2 && vout[0].IsEmpty()); + return (vin.size() > 0 && vout.size() == 2 && vout[0].IsEmpty()); } int GetSigOpCount() const @@ -1126,6 +1127,7 @@ public: int nHeight; int nCheckpoint; // ppcoin: chain auto checkpoint height bool fProofOfStake; // ppcoin: is the block of proof-of-stake type + COutPoint prevoutStake; // block header int nVersion; @@ -1146,6 +1148,7 @@ public: nChainTrust = 0; nCheckpoint = 0; fProofOfStake = true; + prevoutStake.SetNull(); nVersion = 0; hashMerkleRoot = 0; @@ -1165,6 +1168,10 @@ public: nChainTrust = 0; nCheckpoint = 0; fProofOfStake = block.IsProofOfStake(); + if (fProofOfStake) + prevoutStake = block.vtx[1].vin[0].prevout; + else + prevoutStake.SetNull(); nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1313,6 +1320,7 @@ public: READWRITE(nHeight); READWRITE(nCheckpoint); READWRITE(fProofOfStake); + READWRITE(prevoutStake); // block header READWRITE(this->nVersion); -- 1.7.1