]> Git Repo - VerusCoin.git/blobdiff - src/chain.h
Build fix
[VerusCoin.git] / src / chain.h
index d882083e6348f5fcb9f86618d6bfd9ec770cbddd..961afe6c40e776b89f43c9caeda5eb7b24941419 100644 (file)
@@ -1,22 +1,78 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2014 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+// file COPYING or https://www.opensource.org/licenses/mit-license.php .
 
 #ifndef BITCOIN_CHAIN_H
 #define BITCOIN_CHAIN_H
 
+class CChainPower;
+
 #include "arith_uint256.h"
 #include "primitives/block.h"
 #include "pow.h"
 #include "tinyformat.h"
 #include "uint256.h"
+#include "mmr.h"
 
 #include <vector>
 
-#include <boost/foreach.hpp>
-
 static const int SPROUT_VALUE_VERSION = 1001400;
+static const int SAPLING_VALUE_VERSION = 1010100;
+
+class CBlockFileInfo
+{
+public:
+    unsigned int nBlocks;      //!< number of blocks stored in file
+    unsigned int nSize;        //!< number of used bytes of block file
+    unsigned int nUndoSize;    //!< number of used bytes in the undo file
+    unsigned int nHeightFirst; //!< lowest height of block in file
+    unsigned int nHeightLast;  //!< highest height of block in file
+    uint64_t nTimeFirst;       //!< earliest time of block in file
+    uint64_t nTimeLast;        //!< latest time of block in file
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        READWRITE(VARINT(nBlocks));
+        READWRITE(VARINT(nSize));
+        READWRITE(VARINT(nUndoSize));
+        READWRITE(VARINT(nHeightFirst));
+        READWRITE(VARINT(nHeightLast));
+        READWRITE(VARINT(nTimeFirst));
+        READWRITE(VARINT(nTimeLast));
+    }
+
+     void SetNull() {
+         nBlocks = 0;
+         nSize = 0;
+         nUndoSize = 0;
+         nHeightFirst = 0;
+         nHeightLast = 0;
+         nTimeFirst = 0;
+         nTimeLast = 0;
+     }
+
+     CBlockFileInfo() {
+         SetNull();
+     }
+
+     std::string ToString() const;
+
+     /** update statistics (does not update nSize) */
+     void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
+         if (nBlocks==0 || nHeightFirst > nHeightIn)
+             nHeightFirst = nHeightIn;
+         if (nBlocks==0 || nTimeFirst > nTimeIn)
+             nTimeFirst = nTimeIn;
+         nBlocks++;
+         if (nHeightIn > nHeightLast)
+             nHeightLast = nHeightIn;
+         if (nTimeIn > nTimeLast)
+             nTimeLast = nTimeIn;
+     }
+};
 
 struct CDiskBlockPos
 {
@@ -26,7 +82,7 @@ struct CDiskBlockPos
     ADD_SERIALIZE_METHODS;
 
     template <typename Stream, typename Operation>
-    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+    inline void SerializationOp(Stream& s, Operation ser_action) {
         READWRITE(VARINT(nFile));
         READWRITE(VARINT(nPos));
     }
@@ -102,6 +158,104 @@ enum BlockStatus: uint32_t {
 //! Blocks with this validity are assumed to satisfy all consensus rules.
 static const BlockStatus BLOCK_VALID_CONSENSUS = BLOCK_VALID_SCRIPTS;
 
+class CBlockIndex;
+
+// This class provides an accumulator for both the chainwork and the chainPOS value
+// CChainPower's can be compared, and the comparison ensures that work and proof of stake power
+// are both used equally to determine which chain has the most work. This makes an attack
+// that involves mining in secret completely ineffective, even before dPOW, unless a large part 
+// of the staking supply is also controlled. It also enables a faster deterministic convergence, 
+// aided by both POS and POW.
+class CChainPower
+{
+    public:
+        arith_uint256 chainWork;
+        arith_uint256 chainStake;
+        int32_t nHeight;
+
+        CChainPower() : nHeight(0), chainStake(0), chainWork(0) {}
+        CChainPower(CBlockIndex *pblockIndex);
+        CChainPower(CBlockIndex *pblockIndex, const arith_uint256 &stake, const arith_uint256 &work);
+        CChainPower(int32_t height) : nHeight(height), chainStake(0), chainWork(0) {}
+        CChainPower(int32_t height, const arith_uint256 &stake, const arith_uint256 &work) : 
+                    nHeight(height), chainStake(stake), chainWork(work) {}
+
+        CChainPower &operator=(const CChainPower &chainPower)
+        {
+            chainWork = chainPower.chainWork;
+            chainStake = chainPower.chainStake;
+            nHeight = chainPower.nHeight;
+            return *this;
+        }
+
+        CChainPower &operator+=(const CChainPower &chainPower)
+        {
+            this->chainWork += chainPower.chainWork;
+            this->chainStake += chainPower.chainStake;
+            return *this;
+        }
+
+        friend CChainPower operator+(const CChainPower &chainPowerA, const CChainPower &chainPowerB)
+        {
+            CChainPower result = CChainPower(chainPowerA);
+            result.chainWork += chainPowerB.chainWork;
+            result.chainStake += chainPowerB.chainStake;
+            return result;
+        }
+
+        friend CChainPower operator-(const CChainPower &chainPowerA, const CChainPower &chainPowerB)
+        {
+            CChainPower result = CChainPower(chainPowerA);
+            result.chainWork -= chainPowerB.chainWork;
+            result.chainStake -= chainPowerB.chainStake;
+            return result;
+        }
+
+        friend CChainPower operator*(const CChainPower &chainPower, int32_t x)
+        {
+            CChainPower result = CChainPower(chainPower);
+            result.chainWork *= x;
+            result.chainStake *= x;
+            return result;
+        }
+
+        CChainPower &addStake(const arith_uint256 &nChainStake)
+        {
+            chainStake += nChainStake;
+            return *this;
+        }
+
+        CChainPower &addWork(const arith_uint256 &nChainWork)
+        {
+            chainWork += nChainWork;
+            return *this;
+        }
+
+        friend bool operator==(const CChainPower &p1, const CChainPower &p2);
+
+        friend bool operator!=(const CChainPower &p1, const CChainPower &p2)
+        {
+            return !(p1 == p2);
+        }
+
+        friend bool operator<(const CChainPower &p1, const CChainPower &p2);
+
+        friend bool operator<=(const CChainPower &p1, const CChainPower &p2);
+
+        friend bool operator>(const CChainPower &p1, const CChainPower &p2)
+        {
+            return !(p1 <= p2);
+        }
+
+        friend bool operator>=(const CChainPower &p1, const CChainPower &p2)
+        {
+            return !(p1 < p2);
+        }
+
+        uint256 CompactChainPower() const;
+        static CChainPower ExpandCompactPower(uint256 compactPower, uint32_t height = 0);
+};
+
 /** The block chain is a tree shaped structure starting with the
  * genesis block at the root, with each block potentially having multiple
  * candidates to be the next block. A blockindex may have multiple pprev pointing
@@ -119,9 +273,13 @@ public:
     //! pointer to the index of some further predecessor of this block
     CBlockIndex* pskip;
 
-    //! height of the entry in the chain. The genesis block has height 0
-    int nHeight;
-    int64_t newcoins,zfunds;
+    int64_t newcoins;
+    int64_t zfunds;
+    int64_t immature;       // how much in this block is immature
+    uint32_t maturity;      // when do the immature funds in this block mature?
+
+    int8_t segid; // jl777 fields
+
     //! Which # file this block is stored in (blk?????.dat)
     int nFile;
 
@@ -132,7 +290,7 @@ public:
     unsigned int nUndoPos;
 
     //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
-    arith_uint256 nChainWork;
+    CChainPower chainPower;
 
     //! Number of transactions in this block.
     //! Note: in a potential headers-first mode, this number cannot be relied upon
@@ -152,10 +310,10 @@ public:
     boost::optional<uint32_t> nCachedBranchId;
 
     //! The anchor for the tree state up to the start of this block
-    uint256 hashAnchor;
+    uint256 hashSproutAnchor;
 
     //! (memory only) The anchor for the tree state up to the end of this block
-    uint256 hashAnchorEnd;
+    uint256 hashFinalSproutRoot;
 
     //! Change in value held by the Sprout circuit over this block.
     //! Will be boost::none for older blocks on old nodes until a reindex has taken place.
@@ -166,10 +324,19 @@ public:
     //! Will be boost::none if nChainTx is zero.
     boost::optional<CAmount> nChainSproutValue;
 
+    //! Change in value held by the Sapling circuit over this block.
+    //! Not a boost::optional because this was added before Sapling activated, so we can
+    //! rely on the invariant that every block before this was added had nSaplingValue = 0.
+    CAmount nSaplingValue;
+
+    //! (memory only) Total value held by the Sapling circuit up to and including this block.
+    //! Will be boost::none if nChainTx is zero.
+    boost::optional<CAmount> nChainSaplingValue;
+
     //! block header
     int nVersion;
     uint256 hashMerkleRoot;
-    uint256 hashReserved;
+    uint256 hashFinalSaplingRoot;
     unsigned int nTime;
     unsigned int nBits;
     uint256 nNonce;
@@ -182,26 +349,30 @@ public:
     {
         phashBlock = NULL;
         newcoins = zfunds = 0;
+        maturity = 0;
+        immature = 0;
+        segid = -2;
         pprev = NULL;
         pskip = NULL;
-        nHeight = 0;
         nFile = 0;
         nDataPos = 0;
         nUndoPos = 0;
-        nChainWork = arith_uint256();
+        chainPower = CChainPower();
         nTx = 0;
         nChainTx = 0;
         nStatus = 0;
         nCachedBranchId = boost::none;
-        hashAnchor = uint256();
-        hashAnchorEnd = uint256();
+        hashSproutAnchor = uint256();
+        hashFinalSproutRoot = uint256();
         nSequenceId = 0;
         nSproutValue = boost::none;
         nChainSproutValue = boost::none;
+        nSaplingValue = 0;
+        nChainSaplingValue = boost::none;
 
         nVersion       = 0;
         hashMerkleRoot = uint256();
-        hashReserved   = uint256();
+        hashFinalSaplingRoot   = uint256();
         nTime          = 0;
         nBits          = 0;
         nNonce         = uint256();
@@ -219,13 +390,23 @@ public:
 
         nVersion       = block.nVersion;
         hashMerkleRoot = block.hashMerkleRoot;
-        hashReserved   = block.hashReserved;
+        hashFinalSaplingRoot   = block.hashFinalSaplingRoot;
         nTime          = block.nTime;
         nBits          = block.nBits;
         nNonce         = block.nNonce;
         nSolution      = block.nSolution;
     }
 
+    void SetHeight(int32_t height)
+    {
+        this->chainPower.nHeight = height;
+    }
+
+    inline int32_t GetHeight() const
+    {
+        return this->chainPower.nHeight;
+    }
+
     CDiskBlockPos GetBlockPos() const {
         CDiskBlockPos ret;
         if (nStatus & BLOCK_HAVE_DATA) {
@@ -251,7 +432,7 @@ public:
         if (pprev)
             block.hashPrevBlock = pprev->GetBlockHash();
         block.hashMerkleRoot = hashMerkleRoot;
-        block.hashReserved   = hashReserved;
+        block.hashFinalSaplingRoot   = hashFinalSaplingRoot;
         block.nTime          = nTime;
         block.nBits          = nBits;
         block.nNonce         = nNonce;
@@ -288,7 +469,7 @@ public:
     std::string ToString() const
     {
         return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
-            pprev, nHeight,
+            pprev, this->chainPower.nHeight,
             hashMerkleRoot.ToString(),
             GetBlockHash().ToString());
     }
@@ -323,6 +504,67 @@ public:
     CBlockIndex* GetAncestor(int height);
     const CBlockIndex* GetAncestor(int height) const;
 
+    int32_t GetVerusPOSTarget() const
+    {
+        return GetBlockHeader().GetVerusPOSTarget();
+    }
+
+    bool IsVerusPOSBlock() const
+    {
+        return GetBlockHeader().IsVerusPOSBlock();
+    }
+
+    bool GetRawVerusPOSHash(uint256 &ret) const;
+    uint256 GetVerusEntropyHashComponent() const;
+
+    uint256 BlockMMRRoot() const
+    {
+        if (nVersion == CBlockHeader::VERUS_V2)
+        {
+            CPBaaSSolutionDescriptor descr = CConstVerusSolutionVector::GetDescriptor((nSolution));
+            if (descr.version >= CActivationHeight::ACTIVATE_PBAAS)
+            {
+                return descr.hashBlockMMRRoot;
+            }
+        }
+        return hashMerkleRoot;
+    }
+
+    uint256 PrevMMRRoot()
+    {
+        if (nVersion == CBlockHeader::VERUS_V2)
+        {
+            CPBaaSSolutionDescriptor descr = CConstVerusSolutionVector::GetDescriptor(nSolution);
+            if (descr.version >= CActivationHeight::ACTIVATE_PBAAS)
+            {
+                return descr.hashPrevMMRRoot;
+            }
+        }
+        return uint256();
+    }
+
+    // return a node from this block index as is, including hash of merkle root and block hash as well as compact chain power, to put into an MMR
+    ChainMMRNode GetBlockMMRNode() const
+    {
+        uint256 blockHash = GetBlockHash();
+
+        uint256 preHash = ChainMMRNode::HashObj(BlockMMRRoot(), blockHash);
+        uint256 power = ArithToUint256(GetCompactPower(nNonce, nBits, nVersion));
+
+        return ChainMMRNode(ChainMMRNode::HashObj(preHash, power), power);
+    }
+
+    CMMRNodeBranch MMRProofBridge()
+    {
+        // we need to add the block hash on the right, no change to index, as bit is zero
+        return CMMRNodeBranch(CMMRNodeBranch::BRANCH_MMRBLAKE_NODE, 2, 0, std::vector<uint256>({GetBlockHash()}));
+    }
+
+    CMMRNodeBranch BlockProofBridge()
+    {
+        // we need to add the merkle root on the left
+        return CMMRNodeBranch(CMMRNodeBranch::BRANCH_MMRBLAKE_NODE, 2, 1, std::vector<uint256>({BlockMMRRoot()}));
+    }
 };
 
 /** Used to marshal pointers into hashes for db storage. */
@@ -331,7 +573,7 @@ class CDiskBlockIndex : public CBlockIndex
 public:
     uint256 hashPrev;
 
-    CDiskBlockIndex() {
+    CDiskBlockIndex() : CBlockIndex() {
         hashPrev = uint256();
     }
 
@@ -342,11 +584,18 @@ public:
     ADD_SERIALIZE_METHODS;
 
     template <typename Stream, typename Operation>
-    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
-        if (!(nType & SER_GETHASH))
+    inline void SerializationOp(Stream& s, Operation ser_action) {
+        int nVersion = s.GetVersion();
+#ifdef VERUSHASHDEBUG
+        if (!ser_action.ForRead()) printf("Serializing block index %s, stream version: %x\n", ToString().c_str(), nVersion);
+#endif
+        if (!(s.GetType() & SER_GETHASH))
             READWRITE(VARINT(nVersion));
 
-        READWRITE(VARINT(nHeight));
+        if (ser_action.ForRead()) {
+            chainPower = CChainPower();
+        }
+        READWRITE(VARINT(chainPower.nHeight));
         READWRITE(VARINT(nStatus));
         READWRITE(VARINT(nTx));
         if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO))
@@ -367,13 +616,13 @@ public:
                 READWRITE(branchId);
             }
         }
-        READWRITE(hashAnchor);
+        READWRITE(hashSproutAnchor);
 
         // block header
         READWRITE(this->nVersion);
         READWRITE(hashPrev);
         READWRITE(hashMerkleRoot);
-        READWRITE(hashReserved);
+        READWRITE(hashFinalSaplingRoot);
         READWRITE(nTime);
         READWRITE(nBits);
         READWRITE(nNonce);
@@ -381,9 +630,18 @@ public:
 
         // Only read/write nSproutValue if the client version used to create
         // this index was storing them.
-        if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
+        if ((s.GetType() & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
             READWRITE(nSproutValue);
         }
+
+        // Only read/write nSaplingValue if the client version used to create
+        // this index was storing them.
+        if ((s.GetType() & SER_DISK) && (nVersion >= SAPLING_VALUE_VERSION)) {
+            READWRITE(nSaplingValue);
+        }
+
+        // If you have just added new serialized fields above, remember to add
+        // them to CBlockTreeDB::LoadBlockIndexGuts() in txdb.cpp :)
     }
 
     uint256 GetBlockHash() const
@@ -392,7 +650,7 @@ public:
         block.nVersion        = nVersion;
         block.hashPrevBlock   = hashPrev;
         block.hashMerkleRoot  = hashMerkleRoot;
-        block.hashReserved    = hashReserved;
+        block.hashFinalSaplingRoot    = hashFinalSaplingRoot;
         block.nTime           = nTime;
         block.nBits           = nBits;
         block.nNonce          = nNonce;
@@ -400,25 +658,45 @@ public:
         return block.GetHash();
     }
 
-
     std::string ToString() const
     {
-        std::string str = "CDiskBlockIndex(";
-        str += CBlockIndex::ToString();
-        str += strprintf("\n                hashBlock=%s, hashPrev=%s)",
-            GetBlockHash().ToString(),
-            hashPrev.ToString());
+        std::string str = "CDiskBlockIndex:\n";
+
+        CBlockHeader block;
+        block.nVersion        = nVersion;
+        block.hashPrevBlock   = hashPrev;
+        block.hashMerkleRoot  = hashMerkleRoot;
+        block.hashFinalSaplingRoot    = hashFinalSaplingRoot;
+        block.nTime           = nTime;
+        block.nBits           = nBits;
+        block.nNonce          = nNonce;
+        block.nSolution       = nSolution;
+        CPBaaSPreHeader preBlock(block);
+
+        str += strprintf("block.nVersion=%x\npprev=%p\nnHeight=%d\nhashBlock=%s\nblock.hashPrevBlock=%s\nblock.hashMerkleRoot=%s\nblock.nBits=%d\nblock.nNonce=%s\nblock.nSolution=%s\npreBlock.hashPrevMMRRoot=%s\npreBlock.hashBlockMMRRoot=%s\n",
+            this->nVersion, pprev, this->chainPower.nHeight, GetBlockHash().ToString(), hashPrev.ToString(), hashMerkleRoot.ToString(), nBits, nNonce.ToString(), HexBytes(nSolution.data(), nSolution.size()), preBlock.hashPrevMMRRoot.ToString(), preBlock.hashBlockMMRRoot.ToString());
+
         return str;
     }
 };
 
-/** An in-memory indexed chain of blocks. */
+class CChain;
+typedef CMerkleMountainRange<ChainMMRNode, CChunkedLayer<ChainMMRNode, 9>, COverlayNodeLayer<ChainMMRNode, CChain>> ChainMerkleMountainRange;
+typedef CMerkleMountainView<ChainMMRNode, CChunkedLayer<ChainMMRNode, 9>, COverlayNodeLayer<ChainMMRNode, CChain>> ChainMerkleMountainView;
+
+/** An in-memory indexed chain of blocks. 
+ * With Verus and PBaaS chains, this also provides a complete Merkle Mountain Range (MMR) for the chain at all times,
+ * enabling proof of any transaction that can be exported and trusted on any chain that has a trusted oracle or other lite proof of this chain.
+*/
 class CChain {
 private:
     std::vector<CBlockIndex*> vChain;
+    ChainMerkleMountainRange mmr;
     CBlockIndex *lastTip;
 
 public:
+    CChain() : vChain(), mmr(COverlayNodeLayer<ChainMMRNode, CChain>(*this)) {}
+
     /** Returns the index entry for the genesis block of this chain, or NULL if none. */
     CBlockIndex *Genesis() const {
         return vChain.size() > 0 ? vChain[0] : NULL;
@@ -441,6 +719,28 @@ public:
         return vChain[nHeight];
     }
 
+    uint256 GetVerusEntropyHash(int forHeight, int *pPOSheight=nullptr, int *pPOWheight=nullptr, int *pALTheight=nullptr) const;
+
+    /** Get the Merkle Mountain Range for this chain. */
+    const ChainMerkleMountainRange &GetMMR()
+    {
+        return mmr;
+    }
+
+    /** Get a Merkle Mountain Range view for this chain. */
+    ChainMerkleMountainView GetMMV()
+    {
+        return ChainMerkleMountainView(mmr, mmr.size());
+    }    
+
+    ChainMMRNode GetMMRNode(int index) const
+    {
+        return vChain[index]->GetBlockMMRNode();
+    }
+
+    bool GetBlockProof(ChainMerkleMountainView &view, CMMRProof &retProof, int index) const;
+    bool GetMerkleProof(ChainMerkleMountainView &view, CMMRProof &retProof, int index) const;
+
     /** Compare two chains efficiently. */
     friend bool operator==(const CChain &a, const CChain &b) {
         return a.vChain.size() == b.vChain.size() &&
@@ -449,22 +749,27 @@ public:
 
     /** Efficiently check whether a block is present in this chain. */
     bool Contains(const CBlockIndex *pindex) const {
-        return (*this)[pindex->nHeight] == pindex;
+        return !pindex ? false : (*this)[pindex->GetHeight()] == pindex;
     }
 
     /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */
     CBlockIndex *Next(const CBlockIndex *pindex) const {
         if (Contains(pindex))
-            return (*this)[pindex->nHeight + 1];
+            return (*this)[pindex->GetHeight() + 1];
         else
             return NULL;
     }
 
-    /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */
+    /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->GetHeight() : -1. */
     int Height() const {
         return vChain.size() - 1;
     }
 
+    uint64_t size()
+    {
+        return vChain.size();
+    }
+
     /** Set/initialize a chain with a given tip. */
     void SetTip(CBlockIndex *pindex);
 
This page took 0.040745 seconds and 4 git commands to generate.