main: get address deltas between range of block heights
This commit is contained in:
parent
70600ae1ff
commit
98872dac95
|
@ -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"
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
34
src/main.h
34
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 {
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
11
src/txdb.cpp
11
src/txdb.cpp
|
@ -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());
|
||||
|
||||
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));
|
||||
|
|
|
@ -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 ×tampIndex);
|
||||
bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector<uint256> &vect);
|
||||
bool WriteFlag(const std::string &name, bool fValue);
|
||||
|
|
Loading…
Reference in New Issue