diff --git a/src/main.cpp b/src/main.cpp index 330bf6ad1..aa4435843 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -588,13 +588,22 @@ CBlockTreeDB *pblocktree = NULL; #define KOMODO_ZCASH #include "komodo.h" -int64_t komodo_snapshot() +UniValue komodo_snapshot() { + LOCK(cs_main); int64_t total = -1; - if ( pblocktree != 0 ) - total = pblocktree->Snapshot(); - else fprintf(stderr,"null pblocktree start with -addressindex=true\n"); - return(total); + UniValue result(UniValue::VOBJ); + + if (fAddressIndex) { + if ( pblocktree != 0 ) { + result = pblocktree->Snapshot(); + } else { + fprintf(stderr,"null pblocktree start with -addressindex=true\n"); + } + } else { + fprintf(stderr,"getsnapshot requires -addressindex=true\n"); + } + return(result); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 4405a407d..8eeff7877 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -1015,7 +1015,7 @@ UniValue getaddressbalance(const UniValue& params, bool fHelp) } -int32_t komodo_snapshot(); +UniValue komodo_snapshot(); UniValue getsnapshot(const UniValue& params, bool fHelp) { @@ -1026,9 +1026,12 @@ UniValue getsnapshot(const UniValue& params, bool fHelp) "getsnapshot\n" ); } - if ( (total= komodo_snapshot()) >= 0 ) - result.push_back(Pair("total", (double)total/COIN)); - else result.push_back(Pair("error", "no addressindex")); + result = komodo_snapshot(); + if ( result.size() > 0 ) { + result.push_back(Pair("end_time", time(NULL))); + } else { + result.push_back(Pair("error", "no addressindex")); + } return(result); } diff --git a/src/txdb.cpp b/src/txdb.cpp index 31af362ac..cb0358403 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -10,6 +10,7 @@ #include "main.h" #include "pow.h" #include "uint256.h" +#include "core_io.h" #include @@ -398,12 +399,19 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address); -int64_t CBlockTreeDB::Snapshot() +extern UniValue CBlockTreeDB::Snapshot() { - char chType; int64_t total = 0; std::string address; + char chType; int64_t total = 0; int64_t totalAddresses = 0; std::string address; boost::scoped_ptr pcursor(NewIterator()); + std::map addressAmounts; + UniValue result(UniValue::VOBJ); + result.push_back(Pair("start_time", time(NULL))); + + //pcursor->SeekToFirst(); pcursor->SeekToLast(); - fprintf(stderr,"pcursor iterate\n"); + + int64_t startingHeight = chainActive.Height(); + while (pcursor->Valid()) { boost::this_thread::interruption_point(); @@ -411,33 +419,74 @@ int64_t CBlockTreeDB::Snapshot() { leveldb::Slice slKey = pcursor->key(); CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION); - CAddressIndexKey indexKey; + CAddressIndexIteratorKey indexKey; ssKey >> chType; ssKey >> indexKey; - fprintf(stderr,"chType.%d\n",chType); - if ( chType == DB_ADDRESSINDEX ) + + if ( chType == DB_ADDRESSUNSPENTINDEX ) { try { leveldb::Slice slValue = pcursor->value(); CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION); CAmount nValue; ssValue >> nValue; - getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); - fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); - if ( total < 0 ) - total = (int64_t)nValue; - else total += (int64_t)nValue; - //addressIndex.push_back(make_pair(indexKey, nValue)); + + getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); + std::map ::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 + addressAmounts[address] += nValue; + } + + //fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN); + total += nValue; } catch (const std::exception& e) { return error("failed to get address index value"); } } else { break; } } catch (const std::exception& e) { + fprintf(stderr, "%s: LevelDB exception! - %s\n", __func__, e.what()); break; } pcursor->Prev(); } - return(total); + + UniValue addresses(UniValue::VARR); + fprintf(stderr, "total=%f, totalAddresses=%li\n", (double) total / COIN, totalAddresses); + + typedef std::function, std::pair)> Comparator; + Comparator compFunctor = [](std::pair elem1 ,std::pair elem2) { + return elem1.second > elem2.second; /* descending */ + }; + // This is our intermediate data structure that allows us to calculate addressSorted + std::set, Comparator> sortedSnapshot(addressAmounts.begin(), addressAmounts.end(), compFunctor); + + UniValue obj(UniValue::VOBJ); + UniValue addressesSorted(UniValue::VARR); + for (std::pair element : sortedSnapshot) { + UniValue obj(UniValue::VOBJ); + obj.push_back( make_pair("addr", element.first.c_str() ) ); + char amount[32]; + sprintf(amount, "%.8f", (double) element.second / COIN); + obj.push_back( make_pair("amount", amount) ); + addressesSorted.push_back(obj); + } + + result.push_back(make_pair("addresses", addressesSorted)); + result.push_back(make_pair("total", total / COIN )); + result.push_back(make_pair("average",(double) (total/COIN) / totalAddresses )); + // Total number of addresses in this snaphot + result.push_back(make_pair("total_addresses", totalAddresses)); + // 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 ×tampIndex) { diff --git a/src/txdb.h b/src/txdb.h index cb4d6d19e..6c6b41917 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -13,6 +13,7 @@ #include #include #include +#include class CBlockFileInfo; class CBlockIndex; @@ -94,7 +95,7 @@ public: bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); bool blockOnchainActive(const uint256 &hash); - int64_t Snapshot(); + UniValue Snapshot(); }; #endif // BITCOIN_TXDB_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index ce5630fb6..5100a2470 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1885,6 +1885,11 @@ void CWallet::ReacceptWalletTransactions() bool CWalletTx::RelayWalletTransaction() { + if ( pwallet == 0 ) + { + fprintf(stderr,"unexpected null pwallet in RelayWalletTransaction\n"); + return(false); + } assert(pwallet->GetBroadcastTransactions()); if (!IsCoinBase()) { @@ -2124,9 +2129,12 @@ std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) } BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { - CWalletTx& wtx = *item.second; - if (wtx.RelayWalletTransaction()) - result.push_back(wtx.GetHash()); + if ( item.second != 0 ) + { + CWalletTx &wtx = *item.second; + if (wtx.RelayWalletTransaction()) + result.push_back(wtx.GetHash()); + } } return result; }