changeset 29674:db8ab86c45c6

main: spentindex for the mempool
author Braydon Fuller <braydon@bitpay.com>
date Mon, 16 May 2016 14:23:01 -0400
parents 67db818ef672
children 87b51727e811
files qa/rpc-tests/spentindex.py src/Makefile.am src/main.cpp src/main.h src/spentindex.h src/txmempool.cpp src/txmempool.h
diffstat 7 files changed, 200 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/qa/rpc-tests/spentindex.py	Fri May 13 11:43:29 2016 -0400
+++ b/qa/rpc-tests/spentindex.py	Mon May 16 14:23:01 2016 -0400
@@ -95,13 +95,22 @@
         self.nodes[0].importprivkey(privkey)
         signed_tx2 = self.nodes[0].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8"))
         txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True)
+
+        # Check the mempool index
+        self.sync_all()
+        txVerbose3 = self.nodes[1].getrawtransaction(txid2, 1)
+        assert_equal(txVerbose3["vin"][0]["address"], address2)
+        assert_equal(txVerbose3["vin"][0]["value"], Decimal(unspent[0]["amount"]))
+        assert_equal(txVerbose3["vin"][0]["valueSat"], amount)
+
+        # Check the database index
         self.nodes[0].generate(1)
         self.sync_all()
 
-        txVerbose3 = self.nodes[3].getrawtransaction(txid2, 1)
-        assert_equal(txVerbose3["vin"][0]["address"], address2)
-        assert_equal(txVerbose2["vin"][0]["value"], Decimal(unspent[0]["amount"]))
-        assert_equal(txVerbose2["vin"][0]["valueSat"], amount)
+        txVerbose4 = self.nodes[3].getrawtransaction(txid2, 1)
+        assert_equal(txVerbose4["vin"][0]["address"], address2)
+        assert_equal(txVerbose4["vin"][0]["value"], Decimal(unspent[0]["amount"]))
+        assert_equal(txVerbose4["vin"][0]["valueSat"], amount)
 
         print "Passed\n"
 
--- a/src/Makefile.am	Fri May 13 11:43:29 2016 -0400
+++ b/src/Makefile.am	Mon May 16 14:23:01 2016 -0400
@@ -80,6 +80,7 @@
 # bitcoin core #
 BITCOIN_CORE_H = \
   addressindex.h \
+  spentindex.h \
   addrman.h \
   alert.h \
   amount.h \
--- a/src/main.cpp	Fri May 13 11:43:29 2016 -0400
+++ b/src/main.cpp	Mon May 16 14:23:01 2016 -0400
@@ -1415,10 +1415,17 @@
 
         // Store transaction in memory
         pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
+
+        // Add memory address index
         if (fAddressIndex) {
             pool.addAddressIndex(entry, view);
         }
 
+        // Add memory spent index
+        if (fSpentIndex) {
+            pool.addSpentIndex(entry, view);
+        }
+
         // trim mempool and check if tx was trimmed
         if (!fOverrideMempoolLimit) {
             LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
@@ -1460,6 +1467,9 @@
     if (!fSpentIndex)
         return false;
 
+    if (mempool.getSpentIndex(key, value))
+        return true;
+
     if (!pblocktree->ReadSpentIndex(key, value))
         return error("unable to get spent info");
 
--- a/src/main.h	Fri May 13 11:43:29 2016 -0400
+++ b/src/main.h	Mon May 16 14:23:01 2016 -0400
@@ -17,6 +17,7 @@
 #include "script/script_error.h"
 #include "sync.h"
 #include "versionbits.h"
+#include "spentindex.h"
 
 #include <algorithm>
 #include <exception>
@@ -293,81 +294,6 @@
     std::vector<int> vHeightInFlight;
 };
 
-struct CSpentIndexKey {
-    uint256 txid;
-    unsigned int outputIndex;
-
-    ADD_SERIALIZE_METHODS;
-
-    template <typename Stream, typename Operation>
-    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
-        READWRITE(txid);
-        READWRITE(outputIndex);
-    }
-
-    CSpentIndexKey(uint256 t, unsigned int i) {
-        txid = t;
-        outputIndex = i;
-    }
-
-    CSpentIndexKey() {
-        SetNull();
-    }
-
-    void SetNull() {
-        txid.SetNull();
-        outputIndex = 0;
-    }
-
-};
-
-struct CSpentIndexValue {
-    uint256 txid;
-    unsigned int inputIndex;
-    int blockHeight;
-    CAmount satoshis;
-    int addressType;
-    uint160 addressHash;
-
-    ADD_SERIALIZE_METHODS;
-
-    template <typename Stream, typename Operation>
-    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
-        READWRITE(txid);
-        READWRITE(inputIndex);
-        READWRITE(blockHeight);
-        READWRITE(satoshis);
-        READWRITE(addressType);
-        READWRITE(addressHash);
-    }
-
-    CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
-        txid = t;
-        inputIndex = i;
-        blockHeight = h;
-        satoshis = s;
-        addressType = type;
-        addressHash = a;
-    }
-
-    CSpentIndexValue() {
-        SetNull();
-    }
-
-    void SetNull() {
-        txid.SetNull();
-        inputIndex = 0;
-        blockHeight = 0;
-        satoshis = 0;
-        addressType = 0;
-        addressHash.SetNull();
-    }
-
-    bool IsNull() const {
-        return txid.IsNull();
-    }
-};
-
 struct CTimestampIndexIteratorKey {
     unsigned int timestamp;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spentindex.h	Mon May 16 14:23:01 2016 -0400
@@ -0,0 +1,98 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 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_SPENTINDEX_H
+#define BITCOIN_SPENTINDEX_H
+
+#include "uint256.h"
+#include "amount.h"
+
+struct CSpentIndexKey {
+    uint256 txid;
+    unsigned int outputIndex;
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+        READWRITE(txid);
+        READWRITE(outputIndex);
+    }
+
+    CSpentIndexKey(uint256 t, unsigned int i) {
+        txid = t;
+        outputIndex = i;
+    }
+
+    CSpentIndexKey() {
+        SetNull();
+    }
+
+    void SetNull() {
+        txid.SetNull();
+        outputIndex = 0;
+    }
+
+};
+
+struct CSpentIndexValue {
+    uint256 txid;
+    unsigned int inputIndex;
+    int blockHeight;
+    CAmount satoshis;
+    int addressType;
+    uint160 addressHash;
+
+    ADD_SERIALIZE_METHODS;
+
+    template <typename Stream, typename Operation>
+    inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+        READWRITE(txid);
+        READWRITE(inputIndex);
+        READWRITE(blockHeight);
+        READWRITE(satoshis);
+        READWRITE(addressType);
+        READWRITE(addressHash);
+    }
+
+    CSpentIndexValue(uint256 t, unsigned int i, int h, CAmount s, int type, uint160 a) {
+        txid = t;
+        inputIndex = i;
+        blockHeight = h;
+        satoshis = s;
+        addressType = type;
+        addressHash = a;
+    }
+
+    CSpentIndexValue() {
+        SetNull();
+    }
+
+    void SetNull() {
+        txid.SetNull();
+        inputIndex = 0;
+        blockHeight = 0;
+        satoshis = 0;
+        addressType = 0;
+        addressHash.SetNull();
+    }
+
+    bool IsNull() const {
+        return txid.IsNull();
+    }
+};
+
+struct CSpentIndexKeyCompare
+{
+    bool operator()(const CSpentIndexKey& a, const CSpentIndexKey& b) const {
+        if (a.txid == b.txid) {
+            return a.outputIndex < b.outputIndex;
+        } else {
+            return a.txid < b.txid;
+        }
+    }
+};
+
+#endif // BITCOIN_SPENTINDEX_H
--- a/src/txmempool.cpp	Fri May 13 11:43:29 2016 -0400
+++ b/src/txmempool.cpp	Mon May 16 14:23:01 2016 -0400
@@ -496,6 +496,71 @@
     return true;
 }
 
+void CTxMemPool::addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view)
+{
+    LOCK(cs);
+
+    const CTransaction& tx = entry.GetTx();
+    std::vector<CSpentIndexKey> inserted;
+
+    uint256 txhash = tx.GetHash();
+    for (unsigned int j = 0; j < tx.vin.size(); j++) {
+        const CTxIn input = tx.vin[j];
+        const CTxOut &prevout = view.GetOutputFor(input);
+        uint160 addressHash;
+        int addressType;
+
+        if (prevout.scriptPubKey.IsPayToScriptHash()) {
+            addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22));
+            addressType = 2;
+        } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
+            addressHash = uint160(vector<unsigned char> (prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23));
+            addressType = 1;
+        } else {
+            addressHash.SetNull();
+            addressType = 0;
+        }
+
+        CSpentIndexKey key = CSpentIndexKey(input.prevout.hash, input.prevout.n);
+        CSpentIndexValue value = CSpentIndexValue(txhash, j, -1, prevout.nValue, addressType, addressHash);
+
+        mapSpent.insert(make_pair(key, value));
+        inserted.push_back(key);
+
+    }
+
+    mapSpentInserted.insert(make_pair(txhash, inserted));
+}
+
+bool CTxMemPool::getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value)
+{
+    LOCK(cs);
+    mapSpentIndex::iterator it;
+
+    it = mapSpent.find(key);
+    if (it != mapSpent.end()) {
+        value = it->second;
+        return true;
+    }
+    return false;
+}
+
+bool CTxMemPool::removeSpentIndex(const uint256 txhash)
+{
+    LOCK(cs);
+    mapSpentIndexInserted::iterator it = mapSpentInserted.find(txhash);
+
+    if (it != mapSpentInserted.end()) {
+        std::vector<CSpentIndexKey> keys = (*it).second;
+        for (std::vector<CSpentIndexKey>::iterator mit = keys.begin(); mit != keys.end(); mit++) {
+            mapSpent.erase(*mit);
+        }
+        mapSpentInserted.erase(it);
+    }
+
+    return true;
+}
+
 void CTxMemPool::removeUnchecked(txiter it)
 {
     const uint256 hash = it->GetTx().GetHash();
@@ -510,6 +575,7 @@
     nTransactionsUpdated++;
     minerPolicyEstimator->removeTx(hash);
     removeAddressIndex(hash);
+    removeSpentIndex(hash);
 }
 
 // Calculates descendants of entry that are not already in setDescendants, and adds to
--- a/src/txmempool.h	Fri May 13 11:43:29 2016 -0400
+++ b/src/txmempool.h	Mon May 16 14:23:01 2016 -0400
@@ -10,6 +10,7 @@
 #include <set>
 
 #include "addressindex.h"
+#include "spentindex.h"
 #include "amount.h"
 #include "coins.h"
 #include "primitives/transaction.h"
@@ -426,6 +427,12 @@
     typedef std::map<uint256, std::vector<CMempoolAddressDeltaKey> > addressDeltaMapInserted;
     addressDeltaMapInserted mapAddressInserted;
 
+    typedef std::map<CSpentIndexKey, CSpentIndexValue, CSpentIndexKeyCompare> mapSpentIndex;
+    mapSpentIndex mapSpent;
+
+    typedef std::map<uint256, std::vector<CSpentIndexKey> > mapSpentIndexInserted;
+    mapSpentIndexInserted mapSpentInserted;
+
     void UpdateParent(txiter entry, txiter parent, bool add);
     void UpdateChild(txiter entry, txiter child, bool add);
 
@@ -462,6 +469,10 @@
                          std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > &results);
     bool removeAddressIndex(const uint256 txhash);
 
+    void addSpentIndex(const CTxMemPoolEntry &entry, const CCoinsViewCache &view);
+    bool getSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value);
+    bool removeSpentIndex(const uint256 txhash);
+
     void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
     void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
     void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);