aboutsummaryrefslogtreecommitdiff
path: root/src/coins.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/coins.h')
-rw-r--r--src/coins.h314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/coins.h b/src/coins.h
new file mode 100644
index 0000000000..41a422f485
--- /dev/null
+++ b/src/coins.h
@@ -0,0 +1,314 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_COINS_H
+#define BITCOIN_COINS_H
+
+#include <primitives/transaction.h>
+#include <compressor.h>
+#include <core_memusage.h>
+#include <hash.h>
+#include <memusage.h>
+#include <serialize.h>
+#include <uint256.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <unordered_map>
+
+/**
+ * A UTXO entry.
+ *
+ * Serialized format:
+ * - VARINT((coinbase ? 1 : 0) | (height << 1))
+ * - the non-spent CTxOut (via CTxOutCompressor)
+ */
+class Coin
+{
+public:
+ //! unspent transaction output
+ CTxOut out;
+
+ //! whether containing transaction was a coinbase
+ unsigned int fCoinBase : 1;
+
+ //! at which height this containing transaction was included in the active block chain
+ uint32_t nHeight : 31;
+
+ //! construct a Coin from a CTxOut and height/coinbase information.
+ Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
+ Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
+
+ void Clear() {
+ out.SetNull();
+ fCoinBase = false;
+ nHeight = 0;
+ }
+
+ //! empty constructor
+ Coin() : fCoinBase(false), nHeight(0) { }
+
+ bool IsCoinBase() const {
+ return fCoinBase;
+ }
+
+ template<typename Stream>
+ void Serialize(Stream &s) const {
+ assert(!IsSpent());
+ uint32_t code = nHeight * 2 + fCoinBase;
+ ::Serialize(s, VARINT(code));
+ ::Serialize(s, CTxOutCompressor(REF(out)));
+ }
+
+ template<typename Stream>
+ void Unserialize(Stream &s) {
+ uint32_t code = 0;
+ ::Unserialize(s, VARINT(code));
+ nHeight = code >> 1;
+ fCoinBase = code & 1;
+ ::Unserialize(s, CTxOutCompressor(out));
+ }
+
+ bool IsSpent() const {
+ return out.IsNull();
+ }
+
+ size_t DynamicMemoryUsage() const {
+ return memusage::DynamicUsage(out.scriptPubKey);
+ }
+};
+
+class SaltedOutpointHasher
+{
+private:
+ /** Salt */
+ const uint64_t k0, k1;
+
+public:
+ SaltedOutpointHasher();
+
+ /**
+ * This *must* return size_t. With Boost 1.46 on 32-bit systems the
+ * unordered_map will behave unpredictably if the custom hasher returns a
+ * uint64_t, resulting in failures when syncing the chain (#4634).
+ */
+ size_t operator()(const COutPoint& id) const {
+ return SipHashUint256Extra(k0, k1, id.hash, id.n);
+ }
+};
+
+struct CCoinsCacheEntry
+{
+ Coin coin; // The actual cached data.
+ unsigned char flags;
+
+ enum Flags {
+ DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view.
+ FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned).
+ /* Note that FRESH is a performance optimization with which we can
+ * erase coins that are fully spent if we know we do not need to
+ * flush the changes to the parent cache. It is always safe to
+ * not mark FRESH if that condition is not guaranteed.
+ */
+ };
+
+ CCoinsCacheEntry() : flags(0) {}
+ explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
+};
+
+typedef std::unordered_map<COutPoint, CCoinsCacheEntry, SaltedOutpointHasher> CCoinsMap;
+
+/** Cursor for iterating over CoinsView state */
+class CCoinsViewCursor
+{
+public:
+ CCoinsViewCursor(const uint256 &hashBlockIn): hashBlock(hashBlockIn) {}
+ virtual ~CCoinsViewCursor() {}
+
+ virtual bool GetKey(COutPoint &key) const = 0;
+ virtual bool GetValue(Coin &coin) const = 0;
+ virtual unsigned int GetValueSize() const = 0;
+
+ virtual bool Valid() const = 0;
+ virtual void Next() = 0;
+
+ //! Get best block at the time this cursor was created
+ const uint256 &GetBestBlock() const { return hashBlock; }
+private:
+ uint256 hashBlock;
+};
+
+/** Abstract view on the open txout dataset. */
+class CCoinsView
+{
+public:
+ /** Retrieve the Coin (unspent transaction output) for a given outpoint.
+ * Returns true only when an unspent coin was found, which is returned in coin.
+ * When false is returned, coin's value is unspecified.
+ */
+ virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const;
+
+ //! Just check whether a given outpoint is unspent.
+ virtual bool HaveCoin(const COutPoint &outpoint) const;
+
+ //! Retrieve the block hash whose state this CCoinsView currently represents
+ virtual uint256 GetBestBlock() const;
+
+ //! Retrieve the range of blocks that may have been only partially written.
+ //! If the database is in a consistent state, the result is the empty vector.
+ //! Otherwise, a two-element vector is returned consisting of the new and
+ //! the old block hash, in that order.
+ virtual std::vector<uint256> GetHeadBlocks() const;
+
+ //! Do a bulk modification (multiple Coin changes + BestBlock change).
+ //! The passed mapCoins can be modified.
+ virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+
+ //! Get a cursor to iterate over the whole state
+ virtual CCoinsViewCursor *Cursor() const;
+
+ //! As we use CCoinsViews polymorphically, have a virtual destructor
+ virtual ~CCoinsView() {}
+
+ //! Estimate database size (0 if not implemented)
+ virtual size_t EstimateSize() const { return 0; }
+};
+
+
+/** CCoinsView backed by another CCoinsView */
+class CCoinsViewBacked : public CCoinsView
+{
+protected:
+ CCoinsView *base;
+
+public:
+ CCoinsViewBacked(CCoinsView *viewIn);
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
+ bool HaveCoin(const COutPoint &outpoint) const override;
+ uint256 GetBestBlock() const override;
+ std::vector<uint256> GetHeadBlocks() const override;
+ void SetBackend(CCoinsView &viewIn);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ CCoinsViewCursor *Cursor() const override;
+ size_t EstimateSize() const override;
+};
+
+
+/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
+class CCoinsViewCache : public CCoinsViewBacked
+{
+protected:
+ /**
+ * Make mutable so that we can "fill the cache" even from Get-methods
+ * declared as "const".
+ */
+ mutable uint256 hashBlock;
+ mutable CCoinsMap cacheCoins;
+
+ /* Cached dynamic memory usage for the inner Coin objects. */
+ mutable size_t cachedCoinsUsage;
+
+public:
+ CCoinsViewCache(CCoinsView *baseIn);
+
+ /**
+ * By deleting the copy constructor, we prevent accidentally using it when one intends to create a cache on top of a base cache.
+ */
+ CCoinsViewCache(const CCoinsViewCache &) = delete;
+
+ // Standard CCoinsView methods
+ bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
+ bool HaveCoin(const COutPoint &outpoint) const override;
+ uint256 GetBestBlock() const override;
+ void SetBestBlock(const uint256 &hashBlock);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override;
+ CCoinsViewCursor* Cursor() const override {
+ throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
+ }
+
+ /**
+ * Check if we have the given utxo already loaded in this cache.
+ * The semantics are the same as HaveCoin(), but no calls to
+ * the backing CCoinsView are made.
+ */
+ bool HaveCoinInCache(const COutPoint &outpoint) const;
+
+ /**
+ * Return a reference to Coin in the cache, or a pruned one if not found. This is
+ * more efficient than GetCoin.
+ *
+ * Generally, do not hold the reference returned for more than a short scope.
+ * While the current implementation allows for modifications to the contents
+ * of the cache while holding the reference, this behavior should not be relied
+ * on! To be safe, best to not hold the returned reference through any other
+ * calls to this cache.
+ */
+ const Coin& AccessCoin(const COutPoint &output) const;
+
+ /**
+ * Add a coin. Set potential_overwrite to true if a non-pruned version may
+ * already exist.
+ */
+ void AddCoin(const COutPoint& outpoint, Coin&& coin, bool potential_overwrite);
+
+ /**
+ * Spend a coin. Pass moveto in order to get the deleted data.
+ * If no unspent output exists for the passed outpoint, this call
+ * has no effect.
+ */
+ bool SpendCoin(const COutPoint &outpoint, Coin* moveto = nullptr);
+
+ /**
+ * Push the modifications applied to this cache to its base.
+ * Failure to call this method before destruction will cause the changes to be forgotten.
+ * If false is returned, the state of this cache (and its backing view) will be undefined.
+ */
+ bool Flush();
+
+ /**
+ * Removes the UTXO with the given outpoint from the cache, if it is
+ * not modified.
+ */
+ void Uncache(const COutPoint &outpoint);
+
+ //! Calculate the size of the cache (in number of transaction outputs)
+ 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,
+ * so may not be able to calculate this.
+ *
+ * @param[in] tx transaction for which we are checking input total
+ * @return Sum of value of all inputs (scriptSigs)
+ */
+ CAmount GetValueIn(const CTransaction& tx) const;
+
+ //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
+ bool HaveInputs(const CTransaction& tx) const;
+
+private:
+ CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
+};
+
+//! Utility function to add all of a transaction's outputs to a cache.
+// When check is false, this assumes that overwrites are only possible for coinbase transactions.
+// When check is true, the underlying view may be queried to determine whether an addition is
+// an overwrite.
+// TODO: pass in a boolean to limit these possible overwrites to known
+// (pre-BIP34) cases.
+void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
+
+//! Utility function to find any unspent output with a given txid.
+// This function can be quite expensive because in the event of a transaction
+// which is not found in the cache, it can cause up to MAX_OUTPUTS_PER_BLOCK
+// lookups to database, so it should be used with care.
+const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid);
+
+#endif // BITCOIN_COINS_H