Browse Source

Port getsnapshot from KMD to Hush

next
Jonathan "Duke" Leto 6 years ago
parent
commit
94d8710140
  1. 20
      src/main.cpp
  2. 54
      src/rpcmisc.cpp
  3. 1
      src/rpcserver.cpp
  4. 126
      src/txdb.cpp

20
src/main.cpp

@ -1,6 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2017 The Hush developers
// Copyright (c) 2017-2018 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -560,6 +560,24 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
UniValue hush_snapshot(int top)
{
LOCK(cs_main);
int64_t total = -1;
UniValue result(UniValue::VOBJ);
if (fAddressIndex) {
if ( pblocktree != 0 ) {
result = pblocktree->Snapshot(top);
} else {
fprintf(stderr,"null pblocktree! Make sure to start with -addressindex=1\n");
}
} else {
fprintf(stderr,"getsnapshot requires -addressindex=1\n");
}
return(result);
}
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions

54
src/rpcmisc.cpp

@ -1056,3 +1056,57 @@ UniValue getspentinfo(const UniValue& params, bool fHelp)
return obj;
}
UniValue hush_snapshot(int top);
UniValue getsnapshot(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); int64_t total; int32_t top = 0;
if (params.size() > 0 && !params[0].isNull()) {
top = atoi(params[0].get_str().c_str());
if (top <= 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, top must be a positive integer");
}
if ( fHelp || params.size() > 1)
{
throw runtime_error(
"getsnapshot\n"
"\nReturns a snapshot of (address,amount) pairs at current height (requires addressindex to be enabled).\n"
"\nArguments:\n"
" \"top\" (number, optional) Only return this many addresses, i.e. top N richlist\n"
"\nResult:\n"
"{\n"
" \"addresses\": [\n"
" {\n"
" \"addr\": \"t1EBhzvATA8mrfVK82E5TgPzzjtagCL420\",\n"
" \"amount\": \"100.0\"\n"
" },\n"
" {\n"
" \"addr\": \"t1EBhzvATAJmrfVL82E57gPzzjtaggDuke\",\n"
" \"amount\": \"23.45\"\n"
" }\n"
" ],\n"
" \"total\": 123.45 (numeric) Total amount in snapshot\n"
" \"average\": 61.7, (numeric) Average amount in each address \n"
" \"utxos\": 14, (number) Total number of UTXOs in snapshot\n"
" \"total_addresses\": 2, (number) Total number of addresses in snapshot,\n"
" \"start_height\": 91, (number) Block height snapshot began\n"
" \"ending_height\": 91 (number) Block height snapsho finished,\n"
" \"start_time\": 1531982752, (number) Unix epoch time snapshot started\n"
" \"end_time\": 1531982752 (number) Unix epoch time snapshot finished\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getsnapshot","")
+ HelpExampleRpc("getsnapshot", "1000")
);
}
result = hush_snapshot(top);
if ( result.size() > 0 ) {
result.push_back(Pair("end_time", (int) time(NULL)));
} else {
result.push_back(Pair("error", "no addressindex"));
}
return(result);
}

1
src/rpcserver.cpp

@ -335,6 +335,7 @@ static const CRPCCommand vRPCCommands[] =
{ "addressindex", "getaddressdeltas", &getaddressdeltas, false },
{ "addressindex", "getaddresstxids", &getaddresstxids, false },
{ "addressindex", "getaddressbalance", &getaddressbalance, false },
{ "addressindex", "getsnapshot", &getsnapshot, false },
/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },

126
src/txdb.cpp

@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2018 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -397,6 +398,131 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
return true;
}
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address);
extern UniValue CBlockTreeDB::Snapshot(int top)
{
char chType; int64_t total = 0; int64_t totalAddresses = 0; std::string address;
int64_t utxos = 0; int64_t ignoredAddresses;
boost::scoped_ptr<leveldb::Iterator> iter(NewIterator());
std::map <std::string, CAmount> addressAmounts;
std::vector <std::pair<CAmount, std::string>> vaddr;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("start_time", (int) time(NULL)));
// TODO: do we have addresses we want to ignore?
std::map <std::string,int> ignoredMap = {
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1},
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey
};
int64_t startingHeight = chainActive.Height();
//fprintf(stderr, "Starting snapshot at height %lli\n", startingHeight);
for (iter->SeekToLast(); iter->Valid(); iter->Prev())
{
boost::this_thread::interruption_point();
try
{
leveldb::Slice slKey = iter->key();
CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
CAddressIndexIteratorKey indexKey;
ssKey >> chType;
ssKey >> indexKey;
//fprintf(stderr, "chType=%d\n", chType);
if (chType == DB_ADDRESSUNSPENTINDEX)
{
try {
leveldb::Slice slValue = iter->value();
CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
CAmount nValue;
ssValue >> nValue;
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
if (ignored != ignoredMap.end()) {
fprintf(stderr,"ignoring %s\n", address.c_str());
ignoredAddresses++;
continue;
}
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
if (pos == addressAmounts.end()) {
// insert new address + utxo amount
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
addressAmounts[address] = nValue;
totalAddresses++;
} else {
// update unspent tally for this address
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
addressAmounts[address] += nValue;
}
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
// total += nValue;
utxos++;
} catch (const std::exception& e) {
fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what());
break;
}
}
} catch (const std::exception& e) {
fprintf(stderr, "DONE reading index entries\n");
break;
}
}
UniValue addresses(UniValue::VARR);
//fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
for (std::pair<std::string, CAmount> element : addressAmounts) {
vaddr.push_back( make_pair(element.second, element.first) );
}
std::sort(vaddr.rbegin(), vaddr.rend());
UniValue obj(UniValue::VOBJ);
UniValue addressesSorted(UniValue::VARR);
int topN = 0;
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) {
UniValue obj(UniValue::VOBJ);
obj.push_back( make_pair("addr", it->second.c_str() ) );
char amount[32];
sprintf(amount, "%.8f", (double) it->first / COIN);
obj.push_back( make_pair("amount", amount) );
total += it->first;
addressesSorted.push_back(obj);
topN++;
// If requested, only show top N addresses in output JSON
if (top == topN)
break;
}
if (top)
totalAddresses = top;
if (totalAddresses > 0) {
// Array of all addreses with balances
result.push_back(make_pair("addresses", addressesSorted));
// Total amount in this snapshot, which is less than circulating supply if top parameter is used
result.push_back(make_pair("total", (double) total / COIN ));
// Average amount in each address of this snapshot
result.push_back(make_pair("average",(double) (total/COIN) / totalAddresses ));
}
// Total number of utxos processed in this snaphot
result.push_back(make_pair("utxos", utxos));
// Total number of addresses in this snaphot
result.push_back(make_pair("total_addresses", totalAddresses));
// Total number of ignored addresses in this snaphot
result.push_back(make_pair("ignored_addresses", ignoredAddresses));
// The snapshot began at this block height
result.push_back(make_pair("start_height", startingHeight));
// The snapshot finished at this block height
result.push_back(make_pair("ending_height", chainActive.Height()));
return(result);
}
bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey &timestampIndex) {
CLevelDBBatch batch;
batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0);

Loading…
Cancel
Save