PPCoin: New data structure for detection of block spam
authorSunny King <sunnyking9999@gmail.com>
Tue, 1 May 2012 18:50:39 +0000 (19:50 +0100)
committerSunny King <sunnyking9999@gmail.com>
Tue, 1 May 2012 18:50:39 +0000 (19:50 +0100)
src/db.cpp
src/main.cpp
src/main.h

index d4dae8d..d85e4a9 100644 (file)
@@ -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
         {
index ef401cd..111c2ff 100644 (file)
@@ -29,6 +29,7 @@ unsigned int nTransactionsUpdated = 0;
 map<COutPoint, CInPoint> mapNextTx;
 
 map<uint256, CBlockIndex*> mapBlockIndex;
+set<COutPoint> 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.
index 1d8dc96..a7843b5 100644 (file)
@@ -53,6 +53,7 @@ static const int fHaveUPnP = false;
 
 extern CCriticalSection cs_main;
 extern std::map<uint256, CBlockIndex*> mapBlockIndex;
+extern std::set<COutPoint> 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);