changeset 29639:4f8a7d36390b

main: get address deltas between range of block heights
author Braydon Fuller <courier@braydon.com>
date Thu, 24 Mar 2016 15:44:23 -0400
parents 12075709f6b0
children 50328b98c542
files qa/rpc-tests/addressindex.py src/main.cpp src/main.h src/rpcmisc.cpp src/rpcserver.cpp src/rpcserver.h src/txdb.cpp src/txdb.h
diffstat 8 files changed, 121 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/qa/rpc-tests/addressindex.py	Wed Mar 23 14:41:08 2016 -0400
+++ b/qa/rpc-tests/addressindex.py	Thu Mar 24 15:44:23 2016 -0400
@@ -156,6 +156,17 @@
         balance2 = self.nodes[1].getaddressbalance(address2)
         assert_equal(balance2["balance"], change_amount)
 
+        # Check that deltas are returned correctly
+        deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 0, "end": 200})
+        balance3 = 0;
+        for delta in deltas:
+            balance3 += delta["satoshis"]
+        assert_equal(balance3, change_amount)
+
+        # Check that deltas can be returned from range of block heights
+        deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 113, "end": 113})
+        assert_equal(len(deltas), 1);
+
         print "Passed\n"
 
 
--- a/src/main.cpp	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/main.cpp	Thu Mar 24 15:44:23 2016 -0400
@@ -1451,13 +1451,14 @@
     return true;
 }
 
-bool GetAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex)
+bool GetAddressIndex(uint160 addressHash, int type,
+                     std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex, int start, int end)
 {
     if (!fAddressIndex)
-        return error("%s: address index not enabled");
-
-    if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex))
-        return error("%s: unable to get txids for address");
+        return error("address index not enabled");
+
+    if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end))
+        return error("unable to get txids for address");
 
     return true;
 }
--- a/src/main.h	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/main.h	Thu Mar 24 15:44:23 2016 -0400
@@ -359,7 +359,7 @@
     int blockHeight;
     unsigned int txindex;
     uint256 txhash;
-    size_t outindex;
+    size_t index;
     bool spending;
 
     size_t GetSerializeSize(int nType, int nVersion) const {
@@ -373,7 +373,7 @@
         ser_writedata32be(s, blockHeight);
         ser_writedata32be(s, txindex);
         txhash.Serialize(s, nType, nVersion);
-        ser_writedata32(s, outindex);
+        ser_writedata32(s, index);
         char f = spending;
         ser_writedata8(s, f);
     }
@@ -384,19 +384,19 @@
         blockHeight = ser_readdata32be(s);
         txindex = ser_readdata32be(s);
         txhash.Unserialize(s, nType, nVersion);
-        outindex = ser_readdata32(s);
+        index = ser_readdata32(s);
         char f = ser_readdata8(s);
         spending = f;
     }
 
     CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex,
-                     uint256 txid, size_t outputIndex, bool isSpending) {
+                     uint256 txid, size_t indexValue, bool isSpending) {
         type = addressType;
         hashBytes = addressHash;
         blockHeight = height;
         txindex = blockindex;
         txhash = txid;
-        outindex = outputIndex;
+        index = indexValue;
         spending = isSpending;
     }
 
@@ -410,7 +410,7 @@
         blockHeight = 0;
         txindex = 0;
         txhash.SetNull();
-        outindex = 0;
+        index = 0;
         spending = false;
     }
 
@@ -419,14 +419,23 @@
 struct CAddressIndexIteratorKey {
     unsigned int type;
     uint160 hashBytes;
+    bool includeHeight;
+    int blockHeight;
 
     size_t GetSerializeSize(int nType, int nVersion) const {
-        return 21;
+        if (includeHeight) {
+            return 25;
+        } else {
+            return 21;
+        }
     }
     template<typename Stream>
     void Serialize(Stream& s, int nType, int nVersion) const {
         ser_writedata8(s, type);
         hashBytes.Serialize(s, nType, nVersion);
+        if (includeHeight) {
+            ser_writedata32be(s, blockHeight);
+        }
     }
     template<typename Stream>
     void Unserialize(Stream& s, int nType, int nVersion) {
@@ -437,6 +446,14 @@
     CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) {
         type = addressType;
         hashBytes = addressHash;
+        includeHeight = false;
+    }
+
+    CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash, int height) {
+        type = addressType;
+        hashBytes = addressHash;
+        blockHeight = height;
+        includeHeight = true;
     }
 
     CAddressIndexIteratorKey() {
@@ -446,6 +463,7 @@
     void SetNull() {
         type = 0;
         hashBytes.SetNull();
+        includeHeight = false;
     }
 };
 
@@ -580,7 +598,9 @@
 };
 
 bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &hashes);
-bool GetAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex);
+bool GetAddressIndex(uint160 addressHash, int type,
+                     std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
+                     int start = 0, int end = 0);
 
 /** Functions for disk access for blocks */
 bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
--- a/src/rpcmisc.cpp	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/rpcmisc.cpp	Thu Mar 24 15:44:23 2016 -0400
@@ -435,6 +435,66 @@
 
 }
 
+UniValue getaddressdeltas(const UniValue& params, bool fHelp)
+{
+    if (fHelp || params.size() != 1 || !params[0].isObject())
+        throw runtime_error(
+            "getaddressdeltas\n"
+            "\nReturns all changes for an address (requires addressindex to be enabled).\n"
+            "\nResult\n"
+            "[\n"
+            "  {\n"
+            "    \"satoshis\"  (number) The difference of satoshis\n"
+            "    \"txid\"  (string) The related txid\n"
+            "    \"index\"  (number) The related input or output index\n"
+            "    \"height\"  (number) The block height\n"
+            "    \"hash\"  (string) The address hash\n"
+            "    \"type\"  (number) The address type 0 for pubkeyhash 1 for scripthash\n"
+            "  }\n"
+            "]\n"
+        );
+
+
+    UniValue startValue = find_value(params[0].get_obj(), "start");
+    UniValue endValue = find_value(params[0].get_obj(), "end");
+
+    if (!startValue.isNum() || !endValue.isNum()) {
+        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start and end values are expected to be block heights");
+    }
+
+    int start = startValue.get_int();
+    int end = startValue.get_int();
+
+    std::vector<std::pair<uint160, int> > addresses;
+
+    if (!getAddressesFromParams(params, addresses)) {
+        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+    }
+
+    std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
+
+    for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) {
+        if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) {
+            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address");
+        }
+    }
+
+    UniValue result(UniValue::VARR);
+
+    for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) {
+        UniValue delta(UniValue::VOBJ);
+        delta.push_back(Pair("satoshis", it->second));
+        delta.push_back(Pair("txid", it->first.txhash.GetHex()));
+        delta.push_back(Pair("index", it->first.index));
+        delta.push_back(Pair("height", it->first.blockHeight));
+        delta.push_back(Pair("hash", it->first.hashBytes.GetHex()));
+        delta.push_back(Pair("type", (int)it->first.type));
+        result.push_back(delta);
+    }
+
+    return result;
+}
+
 UniValue getaddressbalance(const UniValue& params, bool fHelp)
 {
     if (fHelp || params.size() != 1)
--- a/src/rpcserver.cpp	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/rpcserver.cpp	Thu Mar 24 15:44:23 2016 -0400
@@ -315,6 +315,7 @@
 #endif
 
     /* Address index */
+    { "addressindex",       "getaddressdeltas",       &getaddressdeltas,       false },
     { "addressindex",       "getaddresstxids",        &getaddresstxids,        false },
     { "addressindex",       "getaddressbalance",      &getaddressbalance,      false },
 
--- a/src/rpcserver.h	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/rpcserver.h	Thu Mar 24 15:44:23 2016 -0400
@@ -166,6 +166,7 @@
 extern void EnsureWalletIsUnlocked();
 
 extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
+extern UniValue getaddressdeltas(const UniValue& params, bool fHelp);
 extern UniValue getaddresstxids(const UniValue& params, bool fHelp);
 extern UniValue getaddressbalance(const UniValue& params, bool fHelp);
 
--- a/src/txdb.cpp	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/txdb.cpp	Thu Mar 24 15:44:23 2016 -0400
@@ -172,16 +172,25 @@
     return WriteBatch(batch);
 }
 
-bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex) {
+bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
+                                    std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
+                                    int start, int end) {
 
     boost::scoped_ptr<CDBIterator> pcursor(NewIterator());
 
-    pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash)));
+    if (start > 0 && end > 0) {
+        pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash, start)));
+    } else {
+        pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash)));
+    }
 
     while (pcursor->Valid()) {
         boost::this_thread::interruption_point();
         std::pair<char,CAddressIndexKey> key;
         if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash) {
+            if (end > 0 && key.second.blockHeight > end) {
+                break;
+            }
             CAmount nValue;
             if (pcursor->GetValue(nValue)) {
                 addressIndex.push_back(make_pair(key.second, nValue));
--- a/src/txdb.h	Wed Mar 23 14:41:08 2016 -0400
+++ b/src/txdb.h	Thu Mar 24 15:44:23 2016 -0400
@@ -62,7 +62,9 @@
     bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
     bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
     bool WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
-    bool ReadAddressIndex(uint160 addressHash, int type, std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex);
+    bool ReadAddressIndex(uint160 addressHash, int type,
+                          std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
+                          int start = 0, int end = 0);
     bool WriteTimestampIndex(const CTimestampIndexKey &timestampIndex);
     bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &vect);
     bool WriteFlag(const std::string &name, bool fValue);