From 6db2c41b518397d2ff948fd5a0cc9fa9e858c2ce Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sun, 7 Apr 2019 21:57:17 +0800 Subject: [PATCH] inital commit for getSnapshot2 changes --- src/main.cpp | 114 +++++++++++----------------- src/rpc/misc.cpp | 5 +- src/txdb.cpp | 192 +++++++++++++---------------------------------- src/txdb.h | 2 +- 4 files changed, 98 insertions(+), 215 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e8fe3810c..8fbc0f1dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2967,6 +2967,33 @@ void DisconnectNotarisations(const CBlock &block) } } +int8_t GetAddressType(const CScript &scriptPubKey, CTxDestination &vDest, txnouttype &txType, vector> &vSols) +{ + int8_t keyType = 0; + // some non-standard types, like time lock coinbases, don't solve, but do extract + if ( (Solver(scriptPubKey, txType, vSols) || ExtractDestination(scriptPubKey, vDest)) ) + { + keyType = 1; + if (vDest.which()) + { + // if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned + CKeyID kid; + if (CBitcoinAddress(vDest).GetKeyID(kid)) + { + vSols.push_back(vector(kid.begin(), kid.end())); + } + } + else if (txType == TX_SCRIPTHASH) + { + keyType = 2; + } + else if (txType == TX_CRYPTOCONDITION ) + { + keyType = 3; + } + } + return keyType; +} bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { @@ -3002,20 +3029,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex vector> vSols; CTxDestination vDest; txnouttype txType = TX_PUBKEYHASH; - int keyType = 1; - if ((Solver(out.scriptPubKey, txType, vSols) || ExtractDestination(out.scriptPubKey, vDest)) && txType != TX_MULTISIG) { - if (vDest.which()) - { - CKeyID kid; - if (CBitcoinAddress(vDest).GetKeyID(kid)) - { - vSols.push_back(vector(kid.begin(), kid.end())); - } - } - else if (txType == TX_SCRIPTHASH) - { - keyType = 2; - } + int keyType = GetAddressType(out.scriptPubKey, vDest, txType, vSols); + if ( keyType != 0 ) + { for (auto addr : vSols) { uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr); @@ -3072,23 +3088,9 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex vector> vSols; CTxDestination vDest; txnouttype txType = TX_PUBKEYHASH; - int keyType = 1; - // some non-standard types, like time lock coinbases, don't solve, but do extract - if ((Solver(prevout.scriptPubKey, txType, vSols) || ExtractDestination(prevout.scriptPubKey, vDest))) + int keyType = GetAddressType(prevout.scriptPubKey, vDest, txType, vSols); + if ( keyType != 0 ) { - // if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned - if (vDest.which()) - { - CKeyID kid; - if (CBitcoinAddress(vDest).GetKeyID(kid)) - { - vSols.push_back(vector(kid.begin(), kid.end())); - } - } - else if (txType == TX_SCRIPTHASH) - { - keyType = 2; - } for (auto addr : vSols) { uint160 addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr); @@ -3448,8 +3450,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if (fAddressIndex || fSpentIndex) { - for (size_t j = 0; j < tx.vin.size(); j++) { - + for (size_t j = 0; j < tx.vin.size(); j++) + { const CTxIn input = tx.vin[j]; const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); @@ -3457,25 +3459,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CTxDestination vDest; txnouttype txType = TX_PUBKEYHASH; uint160 addrHash; - int keyType = 0; - // some non-standard types, like time lock coinbases, don't solve, but do extract - if ((Solver(prevout.scriptPubKey, txType, vSols) || ExtractDestination(prevout.scriptPubKey, vDest))) + int keyType = GetAddressType(prevout.scriptPubKey, vDest, txType, vSols); + if ( keyType != 0 ) { - keyType = 1; - - // if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned - if (vDest.which()) - { - CKeyID kid; - if (CBitcoinAddress(vDest).GetKeyID(kid)) - { - vSols.push_back(vector(kid.begin(), kid.end())); - } - } - else if (txType == TX_SCRIPTHASH) - { - keyType = 2; - } for (auto addr : vSols) { addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr); @@ -3485,12 +3471,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // remove address from unspent index addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(keyType, addrHash, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); } - } - if (fSpentIndex) { - // add the spent index to determine the txid and input that spent an output - // and to find the amount and address from an input - spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->GetHeight(), prevout.nValue, keyType, addrHash))); + if (fSpentIndex) { + // add the spent index to determine the txid and input that spent an output + // and to find the amount and address from an input + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->GetHeight(), prevout.nValue, keyType, addrHash))); + } } } } @@ -3541,23 +3527,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin vector> vSols; CTxDestination vDest; txnouttype txType = TX_PUBKEYHASH; - int keyType = 1; - // some non-standard types, like time lock coinbases, don't solve, but do extract - if ((Solver(out.scriptPubKey, txType, vSols) || ExtractDestination(out.scriptPubKey, vDest)) && txType != TX_MULTISIG) + int keyType = GetAddressType(out.scriptPubKey, vDest, txType, vSols); + if ( keyType != 0 ) { - // if we failed to solve, and got a vDest, assume P2PKH or P2PK address returned - if (vDest.which()) - { - CKeyID kid; - if (CBitcoinAddress(vDest).GetKeyID(kid)) - { - vSols.push_back(vector(kid.begin(), kid.end())); - } - } - else if (txType == TX_SCRIPTHASH) - { - keyType = 2; - } for (auto addr : vSols) { addrHash = addr.size() == 20 ? uint160(addr) : Hash160(addr); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 814f7b9b8..cf7c85417 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -853,8 +853,9 @@ bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &addr address = CBitcoinAddress(CScriptID(hash)).ToString(); } else if (type == 1) { address = CBitcoinAddress(CKeyID(hash)).ToString(); - } - else { + } else if (type == 3) { + address = CBitcoinAddress(CKeyID(hash)).ToString(); + } else { return false; } return true; diff --git a/src/txdb.cpp b/src/txdb.cpp index ace04ebdb..c8721c92a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -458,10 +458,10 @@ uint32_t komodo_segid32(char *coinaddr); {"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} \ }; -int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector > &vaddr) +int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold, int32_t top, bool fRPC ,std::vector > &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 iter(NewIterator()); std::map addressAmounts; @@ -482,6 +482,12 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector GetValue(nValue); getAddressFromIndex(indexKey.type, indexKey.hashBytes, address); + if ( indexKey.type == 3 ) + { + cryptoConditionsUTXOs++; + cryptoConditionsTotals += nValue; + continue; + } if ( nValue > dustthreshold ) { std::map ::iterator ignored = ignoredMap.find(address); @@ -508,7 +514,7 @@ int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector element : addressAmounts) vaddr.push_back( make_pair(element.second, element.first) ); std::sort(vaddr.rbegin(), vaddr.rend()); int topN = 0; for (std::vector>::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 iter(NewIterator()); - std::map addressAmounts; + int topN = 0; std::vector > vaddr; UniValue result(UniValue::VOBJ); - result.push_back(Pair("start_time", (int) time(NULL))); - - /* std::map 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()) - { - boost::this_thread::interruption_point(); - try - { - std::vector slKey = std::vector(); - pair 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 ::iterator ignored = ignoredMap.find(address); - if (ignored != ignoredMap.end()) { - fprintf(stderr,"ignoring %s\n", address.c_str()); - ignoredAddresses++; - continue; - } - - 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 - //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 addresses(UniValue::VARR); - //fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses); - - for (std::pair 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>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it) + result.push_back(Pair("start_time", (int) time(NULL))); + if ( Snapshot2(0,top,true,vaddr,result) != 0 ) { - 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 + for (std::vector>::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) ); + addressesSorted.push_back(obj); + topN++; + // If requested, only show top N addresses in output JSON + if ( top == topN ) + break; + } + // 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); } diff --git a/src/txdb.h b/src/txdb.h index 9b80b922b..8b98994a2 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -116,7 +116,7 @@ public: bool LoadBlockIndexGuts(); bool blockOnchainActive(const uint256 &hash); UniValue Snapshot(int top); - int32_t Snapshot2(int64_t dustthreshold,int32_t top,std::vector > &vaddr); + int32_t Snapshot2(int64_t dustthreshold, int32_t top, bool fRPC ,std::vector > &vaddr, UniValue &ret); }; #endif // BITCOIN_TXDB_H