|
|
@ -458,10 +458,10 @@ uint32_t komodo_segid32(char *coinaddr); |
|
|
|
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} \ |
|
|
|
}; |
|
|
|
|
|
|
|
int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <std::pair<CAmount, std::string>> &vaddr) |
|
|
|
int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top, bool fRPC ,std::vector <std::pair<CAmount, std::string>> &vaddr, UniValue &ret) |
|
|
|
{ |
|
|
|
int64_t total = 0; int64_t totalAddresses = 0; std::string address; |
|
|
|
int64_t utxos = 0; int64_t ignoredAddresses = 0; |
|
|
|
int64_t utxos = 0; int64_t ignoredAddresses = 0, cryptoConditionsUTXOs = 0, cryptoConditionsTotals = 0; |
|
|
|
DECLARE_IGNORELIST |
|
|
|
boost::scoped_ptr<CDBIterator> iter(NewIterator()); |
|
|
|
std::map <std::string, CAmount> addressAmounts; |
|
|
@ -482,6 +482,12 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s |
|
|
|
CAmount nValue; |
|
|
|
iter->GetValue(nValue); |
|
|
|
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); |
|
|
|
if ( indexKey.type == 3 ) |
|
|
|
{ |
|
|
|
cryptoConditionsUTXOs++; |
|
|
|
cryptoConditionsTotals += nValue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
if ( nValue > dustthreshold ) |
|
|
|
{ |
|
|
|
std::map <std::string, int>::iterator ignored = ignoredMap.find(address); |
|
|
@ -508,7 +514,7 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s |
|
|
|
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
|
|
|
|
// total += nValue;
|
|
|
|
utxos++; |
|
|
|
} else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str()); |
|
|
|
} //else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str());
|
|
|
|
} |
|
|
|
catch (const std::exception& e) |
|
|
|
{ |
|
|
@ -523,166 +529,70 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <s |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); |
|
|
|
//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()); |
|
|
|
int topN = 0; |
|
|
|
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) |
|
|
|
{ |
|
|
|
//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) );
|
|
|
|
//obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) );
|
|
|
|
//addressesSorted.push_back(obj);
|
|
|
|
total += it->first; |
|
|
|
topN++; |
|
|
|
// If requested, only show top N addresses in output JSON
|
|
|
|
if ( top == topN ) |
|
|
|
break; |
|
|
|
} |
|
|
|
// this is for the snapshot RPC, you can skip this by passing false to the 3rd arugment.
|
|
|
|
// Still needs UniValue defined to use SnapShot2 though, can this be changed to just pass 0?
|
|
|
|
// I tried to make it a pointer, and check if the pointer was 0, but UniValue class didnt like that.
|
|
|
|
if ( fRPC ) |
|
|
|
{ |
|
|
|
// Total amount in this snapshot, which is less than circulating supply if top parameter is used
|
|
|
|
ret.push_back(make_pair("total", (double) total / COIN )); |
|
|
|
// Average amount in each address of this snapshot
|
|
|
|
ret.push_back(make_pair("average",(double) (total/COIN) / totalAddresses )); |
|
|
|
// Total number of utxos processed in this snaphot
|
|
|
|
ret.push_back(make_pair("utxos", utxos)); |
|
|
|
// Total number of addresses in this snaphot
|
|
|
|
ret.push_back(make_pair("total_addresses", top ? top : totalAddresses )); |
|
|
|
// Total number of ignored addresses in this snaphot
|
|
|
|
ret.push_back(make_pair("ignored_addresses", ignoredAddresses)); |
|
|
|
// Total number of crypto condition utxos we skipped
|
|
|
|
ret.push_back(make_pair("skipped_cc_utxos", cryptoConditionsUTXOs)); |
|
|
|
// Total value of skipped crypto condition utxos
|
|
|
|
ret.push_back(make_pair("cc_utxo_value", (double) cryptoConditionsTotals / COIN)); |
|
|
|
// The snapshot finished at this block height
|
|
|
|
ret.push_back(make_pair("ending_height", chainActive.Height())); |
|
|
|
} |
|
|
|
return(topN); |
|
|
|
} |
|
|
|
|
|
|
|
UniValue CBlockTreeDB::Snapshot(int top) |
|
|
|
{ |
|
|
|
int64_t total = 0; int64_t totalAddresses = 0; std::string address; |
|
|
|
int64_t utxos = 0; int64_t ignoredAddresses = 0; |
|
|
|
DECLARE_IGNORELIST |
|
|
|
boost::scoped_ptr<CDBIterator> iter(NewIterator()); |
|
|
|
std::map <std::string, CAmount> addressAmounts; |
|
|
|
int topN = 0; |
|
|
|
std::vector <std::pair<CAmount, std::string>> vaddr; |
|
|
|
UniValue result(UniValue::VOBJ); |
|
|
|
UniValue addressesSorted(UniValue::VARR); |
|
|
|
result.push_back(Pair("start_time", (int) time(NULL))); |
|
|
|
|
|
|
|
/* std::map <std::string,int> ignoredMap = {
|
|
|
|
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, |
|
|
|
{"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, |
|
|
|
{"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, |
|
|
|
{"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, |
|
|
|
{"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, |
|
|
|
{"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, |
|
|
|
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, |
|
|
|
{"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, |
|
|
|
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, |
|
|
|
{"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, |
|
|
|
{"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, |
|
|
|
{"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, |
|
|
|
{"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, |
|
|
|
{"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, |
|
|
|
{"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, |
|
|
|
{"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 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()) |
|
|
|
if ( Snapshot2(0,top,true,vaddr,result) != 0 ) |
|
|
|
{ |
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
try |
|
|
|
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) |
|
|
|
{ |
|
|
|
std::vector<unsigned char> slKey = std::vector<unsigned char>(); |
|
|
|
pair<char, CAddressIndexIteratorKey> keyObj; |
|
|
|
iter->GetKey(keyObj); |
|
|
|
|
|
|
|
char chType = keyObj.first; |
|
|
|
CAddressIndexIteratorKey indexKey = keyObj.second; |
|
|
|
|
|
|
|
//fprintf(stderr, "chType=%d\n", chType);
|
|
|
|
if (chType == DB_ADDRESSUNSPENTINDEX) |
|
|
|
{ |
|
|
|
try { |
|
|
|
CAmount nValue; |
|
|
|
iter->GetValue(nValue); |
|
|
|
|
|
|
|
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); |
|
|
|
|
|
|
|
if (nValue > 0) { |
|
|
|
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++; |
|
|
|
} else { |
|
|
|
fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str()); |
|
|
|
} |
|
|
|
} 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 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) ); |
|
|
|
obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) ); |
|
|
|
addressesSorted.push_back(obj); |
|
|
|
topN++; |
|
|
|
// If requested, only show top N addresses in output JSON
|
|
|
|
if ( top == topN ) |
|
|
|
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) ); |
|
|
|
obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) ); |
|
|
|
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
|
|
|
|
// 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())); |
|
|
|
} else result.push_back(make_pair("error", "problem doing snapshot")); |
|
|
|
return(result); |
|
|
|
} |
|
|
|
|
|
|
|