Pruned transactions serialization support.
authorMASM fan <masmfan@gmail.com>
Sat, 15 Feb 2014 15:56:59 +0000 (19:56 +0400)
committerMASM fan <masmfan@gmail.com>
Sat, 15 Feb 2014 15:56:59 +0000 (19:56 +0400)
src/main.h
src/rpcblockchain.cpp
src/txdb.cpp

index a99e22b..6317b29 100644 (file)
@@ -921,22 +921,33 @@ public:
 
     unsigned int GetSerializeSize(int nType, int nVersion) const {
         unsigned int nSize = 0;
-        unsigned int nMaskSize = 0, nMaskCode = 0;
-        CalcMaskSize(nMaskSize, nMaskCode);
-        bool fFirst = vout.size() > 0 && !vout[0].IsNull();
-        bool fSecond = vout.size() > 1 && !vout[1].IsNull();
-        assert(fFirst || fSecond || nMaskCode);
-        unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fCoinStake ? 1 : 0) + (fSecond ? 4 : 0);
+
         // version
         nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion);
-        // size of header code
-        nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
-        // spentness bitmask
-        nSize += nMaskSize;
-        // txouts themself
-        for (unsigned int i = 0; i < vout.size(); i++)
-            if (!vout[i].IsNull())
-                nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
+
+        if (!IsPruned()) {
+            unsigned int nMaskSize = 0, nMaskCode = 0;
+            CalcMaskSize(nMaskSize, nMaskCode);
+            bool fFirst = vout.size() > 0 && !vout[0].IsNull();
+            bool fSecond = vout.size() > 1 && !vout[1].IsNull();
+
+            assert(fFirst || fSecond || nMaskCode);
+            unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fCoinStake ? 1 : 0) + (fSecond ? 4 : 0);
+            // size of header code
+            nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
+            // spentness bitmask
+            nSize += nMaskSize;
+            // txouts themself
+            for (unsigned int i = 0; i < vout.size(); i++)
+                if (!vout[i].IsNull())
+                    nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion);
+        }
+        else {
+            unsigned int nCode = UINT_MAX;
+            // size of header code
+            nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion);
+        }
+
         // height
         nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
         // timestamp and coinstake flag
@@ -952,24 +963,33 @@ public:
         CalcMaskSize(nMaskSize, nMaskCode);
         bool fFirst = vout.size() > 0 && !vout[0].IsNull();
         bool fSecond = vout.size() > 1 && !vout[1].IsNull();
-        assert(fFirst || fSecond || nMaskCode);
-        unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+
         // version
         ::Serialize(s, VARINT(this->nVersion), nType, nVersion);
-        // header code
-        ::Serialize(s, VARINT(nCode), nType, nVersion);
-        // spentness bitmask
-        for (unsigned int b = 0; b<nMaskSize; b++) {
-            unsigned char chAvail = 0;
-            for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
-                if (!vout[2+b*8+i].IsNull())
-                    chAvail |= (1 << i);
-            ::Serialize(s, chAvail, nType, nVersion);
+
+        if (!IsPruned()) {
+            assert(fFirst || fSecond || nMaskCode);
+            unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0);
+            // header code
+            ::Serialize(s, VARINT(nCode), nType, nVersion);
+            // spentness bitmask
+            for (unsigned int b = 0; b<nMaskSize; b++) {
+                unsigned char chAvail = 0;
+                for (unsigned int i = 0; i < 8 && 2+b*8+i < vout.size(); i++)
+                    if (!vout[2+b*8+i].IsNull())
+                        chAvail |= (1 << i);
+                ::Serialize(s, chAvail, nType, nVersion);
+            }
+            // txouts themself
+            for (unsigned int i = 0; i < vout.size(); i++) {
+                if (!vout[i].IsNull())
+                    ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+            }
         }
-        // txouts themself
-        for (unsigned int i = 0; i < vout.size(); i++) {
-            if (!vout[i].IsNull())
-                ::Serialize(s, CTxOutCompressor(REF(vout[i])), nType, nVersion);
+        else {
+            unsigned int nCode = UINT_MAX;
+            // size of header code
+            ::Serialize(s, VARINT(nCode), nType, nVersion);
         }
         // coinbase height
         ::Serialize(s, VARINT(nHeight), nType, nVersion);
@@ -986,27 +1006,30 @@ public:
         ::Unserialize(s, VARINT(this->nVersion), nType, nVersion);
         // header code
         ::Unserialize(s, VARINT(nCode), nType, nVersion);
-        fCoinBase = nCode & 1;
-        std::vector<bool> vAvail(2, false);
-        vAvail[0] = nCode & 2;
-        vAvail[1] = nCode & 4;
-        unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
-        // spentness bitmask
-        while (nMaskCode > 0) {
-            unsigned char chAvail = 0;
-            ::Unserialize(s, chAvail, nType, nVersion);
-            for (unsigned int p = 0; p < 8; p++) {
-                bool f = (chAvail & (1 << p)) != 0;
-                vAvail.push_back(f);
+        if (nCode != UINT_MAX)
+        {
+            fCoinBase = nCode & 1;
+            std::vector<bool> vAvail(2, false);
+            vAvail[0] = nCode & 2;
+            vAvail[1] = nCode & 4;
+            unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
+            // spentness bitmask
+            while (nMaskCode > 0) {
+                unsigned char chAvail = 0;
+                ::Unserialize(s, chAvail, nType, nVersion);
+                for (unsigned int p = 0; p < 8; p++) {
+                    bool f = (chAvail & (1 << p)) != 0;
+                    vAvail.push_back(f);
+                }
+                if (chAvail != 0)
+                    nMaskCode--;
+            }
+            // txouts themself
+            vout.assign(vAvail.size(), CTxOut());
+            for (unsigned int i = 0; i < vAvail.size(); i++) {
+                if (vAvail[i])
+                    ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
             }
-            if (chAvail != 0)
-                nMaskCode--;
-        }
-        // txouts themself
-        vout.assign(vAvail.size(), CTxOut());
-        for (unsigned int i = 0; i < vAvail.size(); i++) {
-            if (vAvail[i])
-                ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion);
         }
         // coinbase height
         ::Unserialize(s, VARINT(nHeight), nType, nVersion);
@@ -1054,6 +1077,9 @@ public:
     // check whether the entire CCoins is spent
     // note that only !IsPruned() CCoins can be serialized
     bool IsPruned() const {
+        if (vout.size() == 0)
+            return true;
+
         BOOST_FOREACH(const CTxOut &out, vout)
             if (!out.IsNull())
                 return false;
@@ -2064,10 +2090,11 @@ struct CCoinsStats
 {
     int nHeight;
     uint64 nTransactions;
+    uint64 nPrunedTransactions;
     uint64 nTransactionOutputs;
     uint64 nSerializedSize;
 
-    CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
+    CCoinsStats() : nHeight(0), nTransactions(0), nPrunedTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
 };
 
 /** Abstract view on the open txout dataset. */
index 3420ed3..9b3c529 100644 (file)
@@ -320,7 +320,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
     CCoinsStats stats;
     if (pcoinsTip->GetStats(stats)) {
         ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex()));
-        ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions));
+        ret.push_back(Pair("availabletx", (boost::int64_t)stats.nTransactions));
+        ret.push_back(Pair("prunedtx", (boost::int64_t)stats.nPrunedTransactions));
         ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs));
         ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize));
     }
index ff40b6c..83bd898 100644 (file)
@@ -9,10 +9,7 @@
 using namespace std;
 
 void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
-    if (coins.IsPruned())
-        batch.Erase(make_pair('c', hash));
-    else
-        batch.Write(make_pair('c', hash), coins);
+    batch.Write(make_pair('c', hash), coins);
 }
 
 void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
@@ -134,11 +131,15 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
                 ssValue >> coins;
                 uint256 txhash;
                 ssKey >> txhash;
-
-                stats.nTransactions++;
-                BOOST_FOREACH(const CTxOut &out, coins.vout) {
-                    if (!out.IsNull())
-                        stats.nTransactionOutputs++;
+                if (!coins.IsPruned()) {
+                    stats.nTransactions++;
+                    BOOST_FOREACH(const CTxOut &out, coins.vout) {
+                        if (!out.IsNull())
+                            stats.nTransactionOutputs++;
+                    }
+                }
+                else {
+                    stats.nPrunedTransactions++;
                 }
                 stats.nSerializedSize += 32 + slValue.size();
             }