#define BITCOIN_COINS_H
#include "compressor.h"
+#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
#include <boost/foreach.hpp>
#include <boost/unordered_map.hpp>
+#include "zcash/IncrementalMerkleTree.hpp"
/**
* Pruned version of CTransaction: only retains metadata and unspent transaction outputs
return false;
return true;
}
+
+ size_t DynamicMemoryUsage() const {
+ size_t ret = memusage::DynamicUsage(vout);
+ BOOST_FOREACH(const CTxOut &out, vout) {
+ const std::vector<unsigned char> *script = &out.scriptPubKey;
+ ret += memusage::DynamicUsage(*script);
+ }
+ return ret;
+ }
};
class CCoinsKeyHasher
CCoinsCacheEntry() : coins(), flags(0) {}
};
+struct CAnchorsCacheEntry
+{
+ bool entered; // This will be false if the anchor is removed from the cache
+ ZCIncrementalMerkleTree tree; // The tree itself
+ unsigned char flags;
+
+ enum Flags {
+ DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
+ };
+
+ CAnchorsCacheEntry() : entered(false), flags(0) {}
+};
+
+struct CNullifiersCacheEntry
+{
+ bool entered; // If the nullifier is spent or not
+ unsigned char flags;
+
+ enum Flags {
+ DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
+ };
+
+ CNullifiersCacheEntry() : entered(false), flags(0) {}
+};
+
typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap;
+typedef boost::unordered_map<uint256, CAnchorsCacheEntry, CCoinsKeyHasher> CAnchorsMap;
+typedef boost::unordered_map<uint256, CNullifiersCacheEntry, CCoinsKeyHasher> CNullifiersMap;
struct CCoinsStats
{
class CCoinsView
{
public:
+ //! Retrieve the tree at a particular anchored root in the chain
+ virtual bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
+
+ //! Determine whether a nullifier is spent or not
+ virtual bool GetNullifier(const uint256 &nullifier) const;
+
//! Retrieve the CCoins (unspent transaction outputs) for a given txid
virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
//! Retrieve the block hash whose state this CCoinsView currently represents
virtual uint256 GetBestBlock() const;
+ //! Get the current "tip" or the latest anchored tree root in the chain
+ virtual uint256 GetBestAnchor() const;
+
//! Do a bulk modification (multiple CCoins changes + BestBlock change).
//! The passed mapCoins can be modified.
- virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ virtual bool BatchWrite(CCoinsMap &mapCoins,
+ const uint256 &hashBlock,
+ const uint256 &hashAnchor,
+ CAnchorsMap &mapAnchors,
+ CNullifiersMap &mapNullifiers);
//! Calculate statistics about the unspent transaction output set
virtual bool GetStats(CCoinsStats &stats) const;
public:
CCoinsViewBacked(CCoinsView *viewIn);
+ bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
+ bool GetNullifier(const uint256 &nullifier) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
+ uint256 GetBestAnchor() const;
void SetBackend(CCoinsView &viewIn);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(CCoinsMap &mapCoins,
+ const uint256 &hashBlock,
+ const uint256 &hashAnchor,
+ CAnchorsMap &mapAnchors,
+ CNullifiersMap &mapNullifiers);
bool GetStats(CCoinsStats &stats) const;
};
private:
CCoinsViewCache& cache;
CCoinsMap::iterator it;
- CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_);
+ size_t cachedCoinUsage; // Cached memory usage of the CCoins object before modification
+ CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage);
public:
CCoins* operator->() { return &it->second.coins; }
/* Whether this cache has an active modifier. */
bool hasModifier;
+
/**
* Make mutable so that we can "fill the cache" even from Get-methods
* declared as "const".
*/
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
+ mutable uint256 hashAnchor;
+ mutable CAnchorsMap cacheAnchors;
+ mutable CNullifiersMap cacheNullifiers;
+
+ /* Cached dynamic memory usage for the inner CCoins objects. */
+ mutable size_t cachedCoinsUsage;
public:
CCoinsViewCache(CCoinsView *baseIn);
~CCoinsViewCache();
// Standard CCoinsView methods
+ bool GetAnchorAt(const uint256 &rt, ZCIncrementalMerkleTree &tree) const;
+ bool GetNullifier(const uint256 &nullifier) const;
bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool HaveCoins(const uint256 &txid) const;
uint256 GetBestBlock() const;
+ uint256 GetBestAnchor() const;
void SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(CCoinsMap &mapCoins,
+ const uint256 &hashBlock,
+ const uint256 &hashAnchor,
+ CAnchorsMap &mapAnchors,
+ CNullifiersMap &mapNullifiers);
+
+
+ // Adds the tree to mapAnchors and sets the current commitment
+ // root to this root.
+ void PushAnchor(const ZCIncrementalMerkleTree &tree);
+
+ // Removes the current commitment root from mapAnchors and sets
+ // the new current root.
+ void PopAnchor(const uint256 &rt);
+
+ // Marks a nullifier as spent or not.
+ void SetNullifier(const uint256 &nullifier, bool spent);
/**
* Return a pointer to CCoins in the cache, or NULL if not found. This is
//! Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize() const;
+ //! Calculate the size of the cache (in bytes)
+ size_t DynamicMemoryUsage() const;
+
/**
* Amount of bitcoins coming in to a transaction
* Note that lightweight clients may not know anything besides the hash of previous transactions,
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
+ //! Check whether all joinsplit requirements (anchors/nullifiers) are satisfied
+ bool HaveJoinSplitRequirements(const CTransaction& tx) const;
+
//! Return priority of tx at height nHeight
double GetPriority(const CTransaction &tx, int nHeight) const;