Allow free transactions
[novacoin.git] / src / main.h
index 195d62e..ac0140d 100644 (file)
@@ -50,7 +50,7 @@ static const unsigned int STAKE_SWITCH_TIME = 1371686400; // Thu, 20 Jun 2013 00
 static const unsigned int TARGETS_SWITCH_TIME = 1374278400; // Sat, 20 Jul 2013 00:00:00 GMT
 static const unsigned int CHAINCHECKS_SWITCH_TIME = 1379635200; // Fri, 20 Sep 2013 00:00:00 GMT
 static const unsigned int STAKECURVE_SWITCH_TIME = 1382227200; // Sun, 20 Oct 2013 00:00:00 GMT
-static const unsigned int OUTPUT_SWITCH_TIME = 1398916800; // Thu, 01 May 2014 04:00:00 GMT
+static const unsigned int FEE_SWITCH_TIME = 1404172800; // Thu, 01 Jun 2014 00:00:00 GMT
 
 
 inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
@@ -100,13 +100,14 @@ extern int64 nTransactionFee;
 extern int64 nMinimumInputValue;
 extern bool fUseFastIndex;
 extern unsigned int nDerivationMethodIndex;
+extern bool fEnforceCanonical;
 
 // Minimum disk space required - used in CheckDiskSpace()
 static const uint64 nMinDiskSpace = 52428800;
 
 class CReserveKey;
 class CCoinsDB;
-class CChainDB;
+class CBlockTreeDB;
 class CDiskBlockPos;
 class CCoins;
 class CTxUndo;
@@ -139,10 +140,11 @@ std::string GetWarnings(std::string strFor);
 bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow);
 bool SetBestChain(CBlockIndex* pindexNew);
 bool ConnectBestBlock();
+CBlockIndex * InsertBlockIndex(uint256 hash);
 uint256 WantedByOrphan(const CBlock* pblockOrphan);
 const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
 void StakeMiner(CWallet *pwallet);
-void ResendWalletTransactions();
+void ResendWalletTransactions(bool fForce=false);
 
 bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
 
@@ -463,6 +465,11 @@ public:
         return SerializeHash(*this);
     }
 
+    uint256 GetMetaHash() const
+    {
+        return SignatureHash(CScript(), *this, 0, SIGHASH_ALL);
+    }
+
     bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
     {
         // Time based nLockTime implemented in 0.1.6
@@ -783,6 +790,7 @@ public:
  *
  * Serialized format:
  * - VARINT(nVersion)
+ * - VARINT(nFlags)
  * - VARINT(nCode)
  * - unspentness bitvector, for vout[2] and further; least significant byte first
  * - the non-spent CTxOuts (via CTxOutCompressor)
@@ -790,20 +798,26 @@ public:
  * - VARINT(nTime + is_coinstake)
  * - VARINT(nBlockTime)
  *
+ * The nFlag value consists of:
+ * - bit 1: is coinbase
+ * - bit 2: is coinstake
+ * - bit 3: is pruned
+ *
  * The nCode value consists of:
- * - bit 1: IsCoinBase()
  * - bit 2: vout[0] is not spent
  * - bit 4: vout[1] is not spent
  * - The higher bits encode N, the number of non-zero bytes in the following bitvector.
  *   - In case both bit 2 and bit 4 are unset, they encode N-1, as there must be at
  *     least one non-spent output).
  *
- * Example: 0104835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e40f1d75240f1d752
- *          <><><--------------------------------------------><----><------><------>
- *          |  \                  |                            /      /       /
- *     version code            vout[1]                     height timestamp block timestamp
+ * Example: 010004835800816115944e077fe7c803cfa57f29b36bf87c1d358bb85e40f1d75240f1d752
+ *          <><><><--------------------------------------------><----><------><------>
+ *          |  | \                  |                            /      /       /
+ *     version |  code            vout[1]                     height timestamp block timestamp
+ *           flags
  *
  *    - version = 1
+ *    - flags = 4
  *    - code = 4 (vout[1] is not spent, and 0 non-zero bytes of bitvector follow)
  *    - unspentness bitvector: as 0 non-zero bytes follow, it has length 0
  *    - vout[1]: 835800816115944e077fe7c803cfa57f29b36bf87c1d35
@@ -812,17 +826,20 @@ public:
  *               * 816115944e077fe7c803cfa57f29b36bf87c1d35: address uint160
  *    - height = 203998
  *    - time   = 1389883712
+ *    - is_coinbase = 0
  *    - is_coinstake = 0
  *    - block time   = 1389883712
  *
  *
- * Example: 0109044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b40f1d75240f1d752
- *          <><><--><--------------------------------------------------><----------------------------------------------><----><------><------>
- *         /  \   \                     |                                                           |                     /      /       /
- *  version  code  unspentness       vout[4]                                                     vout[16]           height   timestamp block timestamp
+ * Example: 010508044086ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4eebbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa486af3b40f1d75240f1d752
+ *          <><><><--><--------------------------------------------------><----------------------------------------------><----><------><------>
+ *          /  | \   \                     |                                                           |                     /      /       /
+ *     version | code unspentness       vout[4]                                                     vout[16]              height timestamp block timestamp
+ *           flags
  *
  *  - version = 1
- *  - code = 9 (coinbase, neither vout[0] or vout[1] are unspent,
+ *  - flags = 5
+ *  - code = 8 (neither vout[0] or vout[1] are unspent,
  *                2 (1, +1 because both bit 2 and bit 4 are unset) non-zero bitvector bytes follow)
  *  - unspentness bitvector: bits 2 (0x04) and 14 (0x4000) are set, so vout[2+2] and vout[14+2] are unspent
  *  - vout[4]: 86ef97d5790061b01caab50f1b8e9c50a5057eb43c2d9563a4ee
@@ -835,8 +852,22 @@ public:
  *              * 8c988f1a4a4de2161e0f50aac7f17e7f9555caa4: address uint160
  *  - height = 120891
  *  - time   = 1389883712
+ *  - is_coinbase = 1
  *  - is_coinstake = 0
  *  - block time   = 1389883712
+ *
+ * Example: 010686af3b40f1d75240f1d752
+ *          <><><----><------><------>
+ *          /  |    \      |        \
+ *   version flags height timestamp block timestamp
+ *
+ *  - version = 1
+ *  - flags = 6 (00000110)
+ *  - height = 120891
+ *  - time   = 1389883712
+ *  - is_coinbase = 0
+ *  - is_coinstake = 1
+ *  - block time   = 1389883712
  */
 class CCoins
 {
@@ -871,7 +902,7 @@ public:
 
     // remove spent outputs at the end of vout
     void Cleanup() {
-        while (vout.size() > 0 && vout.back().IsNull())
+        while (vout.size() > 0 && (vout.back().IsNull() || vout.back().IsEmpty()))
             vout.pop_back();
     }
 
@@ -920,101 +951,158 @@ 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);
+        bool fPruned = IsPruned();
+
         // 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);
-        // height
-        nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
-        // timestamp and coinstake flag
-        nSize += ::GetSerializeSize(VARINT(nTime*2+(fCoinStake ? 1 : 0)), nType, nVersion);
-        // block timestamp
-        nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+        unsigned char nFlags = 0;
+        // coinbase, coinstake and prune flags
+        nFlags = (fCoinBase ? 1 : 0)<<0 | (fCoinStake ? 1 : 0)<<1 | (fPruned ? 1 : 0)<<2;
+        // size of flags
+        nSize += ::GetSerializeSize(VARINT(nFlags), 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)) + (fFirst ? 2 : 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);
+            // height
+            nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
+            // timestamp and coinstake flag
+            nSize += ::GetSerializeSize(VARINT(nTime), nType, nVersion);
+            // block timestamp
+            nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+        }
+        else {
+            // size of height
+            nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion);
+            // size of timestamp
+            nSize += ::GetSerializeSize(VARINT(nTime), nType, nVersion);
+            // size of block timestamp
+            nSize += ::GetSerializeSize(VARINT(nBlockTime), nType, nVersion);
+        }
+
         return nSize;
     }
 
     template<typename Stream>
     void Serialize(Stream &s, int nType, int nVersion) const {
-        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) + (fSecond ? 4 : 0);
+        bool fPruned = IsPruned();
+        unsigned char nFlags = 0;
+        nFlags = (fCoinBase ? 1 : 0)<<0 | (fCoinStake ? 1 : 0)<<1 | (fPruned ? 1 : 0)<<2;
+
         // 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);
+        // flags
+        ::Serialize(s, VARINT(nFlags), nType, nVersion);
+
+        if (!fPruned) {
+            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)) + (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);
+            }
+            // coinbase height
+            ::Serialize(s, VARINT(nHeight), nType, nVersion);
+            // transaction timestamp and coinstake flag
+            ::Serialize(s, VARINT(nTime), nType, nVersion);
+            // block timestamp
+            ::Serialize(s, VARINT(nBlockTime), 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 {
+            // coinbase height
+            ::Serialize(s, VARINT(nHeight), nType, nVersion);
+            // transaction timestamp
+            ::Serialize(s, VARINT(nTime), nType, nVersion);
+            // block timestamp
+            ::Serialize(s, VARINT(nBlockTime), nType, nVersion);
         }
-        // coinbase height
-        ::Serialize(s, VARINT(nHeight), nType, nVersion);
-        // transaction timestamp and coinstake flag
-        ::Serialize(s, VARINT(nTime*2+(fCoinStake ? 1 : 0)), nType, nVersion);
-        // block time
-        ::Serialize(s, VARINT(nBlockTime), nType, nVersion);
     }
 
     template<typename Stream>
     void Unserialize(Stream &s, int nType, int nVersion) {
-        unsigned int nCode = 0, nCodeTime = 0;
+        unsigned char nFlags = 0;
+
         // version
         ::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);
+        // coinbase and coinstake flags
+        ::Unserialize(s, VARINT(nFlags), nType, nVersion);
+
+        fCoinBase = nFlags & (1<<0);
+        fCoinStake = nFlags & (1<<1);
+        bool fPruned = nFlags & (1<<2);
+
+        if (!fPruned) {
+            unsigned int nCode = 0;
+            // header code
+            ::Unserialize(s, VARINT(nCode), nType, nVersion);
+            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--;
+            // coinbase height
+            ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+            // transaction timestamp
+            ::Unserialize(s, VARINT(nTime), nType, nVersion);
+            nTime = nTime;
+            // block timestamp
+            ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
         }
-        // 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);
+        else {
+            // coinbase height
+            ::Unserialize(s, VARINT(nHeight), nType, nVersion);
+            // transaction timestamp
+            ::Unserialize(s, VARINT(nTime), nType, nVersion);
+            // block timestamp
+            ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
         }
-        // coinbase height
-        ::Unserialize(s, VARINT(nHeight), nType, nVersion);
-        // transaction timestamp
-        ::Unserialize(s, VARINT(nCodeTime), nType, nVersion);
-        nTime = nCodeTime / 2;
-        fCoinStake = nCodeTime & 1;
-        // block timestamp
-        ::Unserialize(s, VARINT(nBlockTime), nType, nVersion);
         Cleanup();
     }
 
@@ -1053,9 +1141,13 @@ 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;
+
         return true;
     }
 };
@@ -1204,29 +1296,9 @@ public:
 
     void UpdateTime(const CBlockIndex* pindexPrev);
 
-    // ppcoin: entropy bit for stake modifier if chosen by modifier
-    unsigned int GetStakeEntropyBit(unsigned int nTime) const
-    {
-        // Protocol switch to support p2pool at novacoin block #9689
-        if (nTime >= ENTROPY_SWITCH_TIME || fTestNet)
-        {
-            // Take last bit of block hash as entropy bit
-            unsigned int nEntropyBit = ((GetHash().Get64()) & 1llu);
-            if (fDebug && GetBoolArg("-printstakemodifier"))
-                printf("GetStakeEntropyBit: nTime=%u hashBlock=%s nEntropyBit=%u\n", nTime, GetHash().ToString().c_str(), nEntropyBit);
-            return nEntropyBit;
-        }
-        // Before novacoin block #9689 - old protocol
-        uint160 hashSig = Hash160(vchBlockSig);
-        if (fDebug && GetBoolArg("-printstakemodifier"))
-            printf("GetStakeEntropyBit: hashSig=%s", hashSig.ToString().c_str());
-        hashSig >>= 159; // take the first bit of the hash
-        if (fDebug && GetBoolArg("-printstakemodifier"))
-            printf(" entropybit=%"PRI64d"\n", hashSig.Get64());
-        return hashSig.Get64();
-    }
+    unsigned int GetStakeEntropyBit(unsigned int nTime) const;
 
-    // ppcoin: two types of block: proof-of-work or proof-of-stake
+    // two types of block: proof-of-work or proof-of-stake
     bool IsProofOfStake() const
     {
         return (vtx.size() > 1 && vtx[1].IsCoinStake());
@@ -1242,7 +1314,7 @@ public:
         return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0);
     }
 
-    // ppcoin: get max transaction timestamp
+    // get max transaction timestamp
     int64 GetMaxTransactionTime() const
     {
         int64 maxTransactionTime = 0;
@@ -2059,6 +2131,17 @@ public:
 
 extern CTxMemPool mempool;
 
+struct CCoinsStats
+{
+    int nHeight;
+    uint64 nTransactions;
+    uint64 nPrunedTransactions;
+    uint64 nTransactionOutputs;
+    uint64 nSerializedSize;
+
+    CCoinsStats() : nHeight(0), nTransactions(0), nPrunedTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
+};
+
 /** Abstract view on the open txout dataset. */
 class CCoinsView
 {
@@ -2079,6 +2162,7 @@ public:
     // Modify the currently active block index
     virtual bool SetBestBlock(CBlockIndex *pindex);
     virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+    virtual bool GetStats(CCoinsStats &stats);
 };
 
 /** CCoinsView backed by another CCoinsView */
@@ -2096,6 +2180,7 @@ public:
     bool SetBestBlock(CBlockIndex *pindex);
     void SetBackend(CCoinsView &viewIn);
     bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+    bool GetStats(CCoinsStats &stats);
 };
 
 /** CCoinsView that adds a memory cache for transactions to another CCoinsView */
@@ -2135,6 +2220,10 @@ public:
     bool HaveCoins(uint256 txid);
 };
 
+/** Global variable that points to the active CCoinsView (protected by cs_main) */
 extern CCoinsViewCache *pcoinsTip;
 
+/** Global variable that points to the active block tree (protected by cs_main) */
+extern CBlockTreeDB *pblocktree;
+
 #endif