main: get address deltas between range of block heights

This commit is contained in:
Braydon Fuller 2016-03-24 15:44:23 -04:00 committed by Simon
parent 70600ae1ff
commit 98872dac95
7 changed files with 120 additions and 15 deletions

View File

@ -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"

View File

@ -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<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");
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;
}

View File

@ -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<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) {
@ -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<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(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);

View File

@ -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<std::pair<uint16
}
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)

View File

@ -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);

View File

@ -302,16 +302,25 @@ bool CBlockTreeDB::WriteAddressIndex(const std::vector<std::pair<CAddressIndexKe
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));

View File

@ -75,7 +75,9 @@ public:
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);