From 98872dac958550c2683919599b0554c54f17903d Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Thu, 24 Mar 2016 15:44:23 -0400 Subject: [PATCH] main: get address deltas between range of block heights --- qa/rpc-tests/addressindex.py | 11 +++++++ src/main.cpp | 9 +++--- src/main.h | 36 ++++++++++++++++----- src/rpc/misc.cpp | 61 ++++++++++++++++++++++++++++++++++++ src/rpcserver.h | 1 + src/txdb.cpp | 13 ++++++-- src/txdb.h | 4 ++- 7 files changed, 120 insertions(+), 15 deletions(-) diff --git a/qa/rpc-tests/addressindex.py b/qa/rpc-tests/addressindex.py index 0ffbcffd7..4fc4cc557 100755 --- a/qa/rpc-tests/addressindex.py +++ b/qa/rpc-tests/addressindex.py @@ -156,6 +156,17 @@ class AddressIndexTest(BitcoinTestFramework): 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" diff --git a/src/main.cpp b/src/main.cpp index f7b2af8ac..4260f6fb1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1595,13 +1595,14 @@ bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::v return true; } -bool GetAddressIndex(uint160 addressHash, int type, std::vector > &addressIndex) +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, int start, int end) { if (!fAddressIndex) - return error("%s: address index not enabled"); + return error("address index not enabled"); - if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex)) - return error("%s: unable to get txids for address"); + if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end)) + return error("unable to get txids for address"); return true; } diff --git a/src/main.h b/src/main.h index 90fce90d3..4d892810b 100644 --- a/src/main.h +++ b/src/main.h @@ -337,7 +337,7 @@ struct CAddressIndexKey { int blockHeight; unsigned int txindex; uint256 txhash; - size_t outindex; + size_t index; bool spending; size_t GetSerializeSize(int nType, int nVersion) const { @@ -351,7 +351,7 @@ struct CAddressIndexKey { 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); } @@ -362,19 +362,19 @@ struct CAddressIndexKey { 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; } @@ -388,7 +388,7 @@ struct CAddressIndexKey { blockHeight = 0; txindex = 0; txhash.SetNull(); - outindex = 0; + index = 0; spending = false; } @@ -397,14 +397,23 @@ struct CAddressIndexKey { 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 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 void Unserialize(Stream& s, int nType, int nVersion) { @@ -415,6 +424,14 @@ struct CAddressIndexIteratorKey { 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() { @@ -424,6 +441,7 @@ struct CAddressIndexIteratorKey { void SetNull() { type = 0; hashBytes.SetNull(); + includeHeight = false; } }; @@ -591,7 +609,9 @@ public: }; bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes); -bool GetAddressIndex(uint160 addressHash, int type, std::vector > &addressIndex); +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start = 0, int end = 0); /** Functions for disk access for blocks */ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index bc981dd08..327b2ed5d 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -495,6 +495,7 @@ static const CRPCCommand commands[] = /* Address index */ { "addressindex", "getaddresstxids", &getaddresstxids, false }, /* insight explorer */ { "addressindex", "getaddressbalance", &getaddressbalance, false }, /* insight explorer */ + { "addressindex", "getaddressdeltas", &getaddressdeltas, false }, /* insight explorer */ /* Not shown in help */ { "hidden", "setmocktime", &setmocktime, true }, @@ -544,6 +545,66 @@ bool getAddressesFromParams(const UniValue& params, std::vector > addresses; + + if (!getAddressesFromParams(params, addresses)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); + } + + std::vector > addressIndex; + + for (std::vector >::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 >::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) diff --git a/src/rpcserver.h b/src/rpcserver.h index 2e757c4ed..fe38cc2c3 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -173,6 +173,7 @@ extern std::string HelpExampleRpc(const std::string& methodname, const std::stri 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); diff --git a/src/txdb.cpp b/src/txdb.cpp index 8eb146b29..62ba48b96 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -302,16 +302,25 @@ bool CBlockTreeDB::WriteAddressIndex(const std::vector > &addressIndex) { +bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start, int end) { boost::scoped_ptr 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 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)); diff --git a/src/txdb.h b/src/txdb.h index 8d16f3820..7911714ac 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -75,7 +75,9 @@ public: bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); bool WriteTxIndex(const std::vector > &list); bool WriteAddressIndex(const std::vector > &vect); - bool ReadAddressIndex(uint160 addressHash, int type, std::vector > &addressIndex); + bool ReadAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start = 0, int end = 0); bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &vect); bool WriteFlag(const std::string &name, bool fValue);