diff --git a/CMakeLists.txt b/CMakeLists.txt index b6d45bd..bc87ee9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(POLICY CMP0167) endif() project(Triangles - VERSION 5.8.1.0 + VERSION 5.8.2 DESCRIPTION "Cryptographic Triangles Wallet" LANGUAGES C CXX ) diff --git a/src/clientversion.h b/src/clientversion.h index add6f48..1f31b6e 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -8,7 +8,7 @@ // These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 5 #define CLIENT_VERSION_MINOR 8 -#define CLIENT_VERSION_REVISION 1 +#define CLIENT_VERSION_REVISION 2 #define CLIENT_VERSION_BUILD 0 // Converts the parameter X to a string after macro replacement on X has been performed. diff --git a/src/init.cpp b/src/init.cpp index c4414ca..5cdd32a 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -952,6 +952,18 @@ bool AppInit2() return false; } + // Handle -reindex: delete the LevelDB block index so it gets rebuilt + // from the raw blk*.dat files via FastImportBlockFile(). + // This recalculates money supply, tx index, and UTXO set from scratch. + if (GetBoolArg("-reindex", false)) + { + printf("Reindex requested: removing block index database...\n"); + uiInterface.InitMessage(_("Removing block index for reindex...")); + fs::path txleveldbPath = GetDataDir() / "txleveldb"; + if (fs::exists(txleveldbPath)) + fs::remove_all(txleveldbPath); + } + uiInterface.InitMessage(_("Loading block index...")); printf("Loading block index...\n"); nStart = GetTimeMillis(); diff --git a/src/main.cpp b/src/main.cpp index d27f05c..06f18e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2324,7 +2324,15 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) { - printf("REORGANIZE\n"); + printf("REORGANIZE: Switching chains\n"); + printf(" Old tip: %s height %d trust %s\n", + pindexBest->GetBlockHash().ToString().substr(0,20).c_str(), + pindexBest->nHeight, + CBigNum(pindexBest->nChainTrust).ToString().c_str()); + printf(" New tip: %s height %d trust %s\n", + pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), + pindexNew->nHeight, + CBigNum(pindexNew->nChainTrust).ToString().c_str()); // Find the fork CBlockIndex* pfork = pindexBest; @@ -2351,8 +2359,17 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) vConnect.push_back(pindex); reverse(vConnect.begin(), vConnect.end()); - printf("REORGANIZE: Disconnect %" PRIszu " blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); - printf("REORGANIZE: Connect %" PRIszu " blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Fork point at height %d: %s\n", + pfork->nHeight, + pfork->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Disconnect %" PRIszu " blocks (heights %d..%d)\n", + vDisconnect.size(), + pfork->nHeight + 1, + pindexBest->nHeight); + printf("REORGANIZE: Connect %" PRIszu " blocks (heights %d..%d)\n", + vConnect.size(), + pfork->nHeight + 1, + pindexNew->nHeight); // Disconnect shorter branch vector vResurrect; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 0053a42..841dccc 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -360,6 +360,49 @@ Value gettxoutsetinfo(const Array& params, bool fHelp) return obj; } +Value recalculatesupply(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "recalculatesupply\n" + "Recalculates the money supply by summing all unspent transaction outputs.\n" + "Updates the stored money supply value at the chain tip and persists it to disk.\n" + "Returns the old and new supply values for comparison.\n" + "\nWARNING: This modifies blockchain index state. Only use if money supply is incorrect."); + + if (!pindexBest) + throw runtime_error("recalculatesupply: no best block"); + + int nUtxoCount = 0; + CTxDB txdb; + int64_t nCalculatedSupply = txdb.SumUtxoValues(nUtxoCount); + int64_t nOldSupply = pindexBest->nMoneySupply; + int64_t nDifference = nCalculatedSupply - nOldSupply; + + // Sanity check: difference should be reasonable (not millions of TRI) + // Max supply is 2,222,222 TRI, so any difference > 1M TRI is suspicious + if (abs64(nDifference) > 1000000 * COIN) + throw runtime_error(strprintf( + "recalculatesupply: calculated supply differs by %s TRI - this is abnormal, refusing to update", + FormatMoney(abs64(nDifference)).c_str())); + + // Update the chain tip's money supply + pindexBest->nMoneySupply = nCalculatedSupply; + + // Persist to LevelDB + CTxDB txdbWrite; + if (!txdbWrite.WriteBlockIndex(CDiskBlockIndex(pindexBest))) + throw runtime_error("recalculatesupply: failed to write updated block index"); + + Object result; + result.push_back(Pair("height", (int)nBestHeight)); + result.push_back(Pair("old_supply", ValueFromAmount(nOldSupply))); + result.push_back(Pair("new_supply", ValueFromAmount(nCalculatedSupply))); + result.push_back(Pair("difference", ValueFromAmount(nDifference))); + result.push_back(Pair("utxo_count", nUtxoCount)); + return result; +} + // triangles: get information of sync-checkpoint Value getcheckpoint(const Array& params, bool fHelp) { diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 16920a6..12b9dbd 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -78,7 +78,8 @@ Value getstakinginfo(const Array& params, bool fHelp) if (fHelp || params.size() != 0) throw runtime_error( "getstakinginfo\n" - "Returns an object containing staking-related information."); + "Returns an object containing staking-related information.\n" + "Includes diagnostic details about why staking may be disabled."); uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0; pwalletMain->GetStakeWeight(*pwalletMain, nMinWeight, nMaxWeight, nWeight); @@ -87,6 +88,26 @@ Value getstakinginfo(const Array& params, bool fHelp) bool staking = nLastCoinStakeSearchInterval && nWeight; int nExpectedTime = staking ? (nTargetSpacing * nNetworkWeight / nWeight) : -1; + // Diagnostic: determine why staking might be disabled + Array stakingDisabledReasons; + if (!GetBoolArg("-staking", true)) + stakingDisabledReasons.push_back("staking disabled via -staking=0 flag"); + + if (pwalletMain->IsLocked()) + stakingDisabledReasons.push_back("wallet is locked (use walletpassphrase true)"); + + if (vNodes.empty()) + stakingDisabledReasons.push_back("no network connections (need at least 1 peer)"); + + if (IsInitialBlockDownload()) + stakingDisabledReasons.push_back("initial block download in progress"); + + if (nWeight == 0) + stakingDisabledReasons.push_back("no mature coins available (coins need 520 confirmations)"); + + if (!staking && nLastCoinStakeSearchInterval == 0) + stakingDisabledReasons.push_back("stake miner thread not running"); + Object obj; obj.push_back(Pair("enabled", GetBoolArg("-staking", true))); @@ -105,6 +126,16 @@ Value getstakinginfo(const Array& params, bool fHelp) obj.push_back(Pair("expectedtime", nExpectedTime)); + // Add detailed diagnostics + obj.push_back(Pair("walletlocked", pwalletMain->IsLocked())); + obj.push_back(Pair("walletunlockedforstakingonly", pwalletMain->fWalletUnlockStakingOnly)); + obj.push_back(Pair("connections", (int)vNodes.size())); + obj.push_back(Pair("initialblockdownload", IsInitialBlockDownload())); + obj.push_back(Pair("maturecoins", nWeight > 0)); + + if (!stakingDisabledReasons.empty()) + obj.push_back(Pair("staking_disabled_reasons", stakingDisabledReasons)); + return obj; } diff --git a/src/trianglesrpc.cpp b/src/trianglesrpc.cpp index 605e9f3..0701ac9 100644 --- a/src/trianglesrpc.cpp +++ b/src/trianglesrpc.cpp @@ -317,6 +317,7 @@ static const CRPCCommand vRPCCommands[] = { "getchaintips", &getchaintips, true, false }, { "invalidateblock", &invalidateblock, false, false }, { "reconsiderblock", &reconsiderblock, false, false }, + { "recalculatesupply", &recalculatesupply, false, false }, { "reservebalance", &reservebalance, false, true}, { "checkwallet", &checkwallet, false, true}, { "repairwallet", &repairwallet, false, true}, diff --git a/src/trianglesrpc.h b/src/trianglesrpc.h index ab0ba0d..2ec8d80 100644 --- a/src/trianglesrpc.h +++ b/src/trianglesrpc.h @@ -225,6 +225,7 @@ extern json_spirit::Value getcheckpoint(const json_spirit::Array& params, bool f extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value recalculatesupply(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getaddressbalance(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getaddressutxos(const json_spirit::Array& params, bool fHelp); diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index e99dde4..a95afa8 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -904,3 +904,35 @@ bool CTxDB::HaveUtxo(const uint256& hash, unsigned int n) return false; } +int64_t CTxDB::SumUtxoValues(int& nCount) +{ + nCount = 0; + int64_t nTotal = 0; + + // Seek to the start of UTXO entries (key prefix "u") + CDataStream ssKeyPrefix(SER_DISK, CLIENT_VERSION); + ssKeyPrefix << make_pair(string("u"), make_pair(uint256(0), (unsigned int)0)); + std::string strPrefixBegin = ssKeyPrefix.str(); + + leveldb::Iterator* it = pdb->NewIterator(leveldb::ReadOptions()); + for (it->Seek(strPrefixBegin); it->Valid(); it->Next()) + { + // Check key prefix is still "u" + CDataStream ssKey(it->key().data(), it->key().data() + it->key().size(), SER_DISK, CLIENT_VERSION); + std::string strKeyType; + ssKey >> strKeyType; + if (strKeyType != "u") + break; + + // Deserialize the UTXO entry and sum the value + CDataStream ssValue(it->value().data(), it->value().data() + it->value().size(), SER_DISK, CLIENT_VERSION); + CUtxoEntry entry; + ssValue >> entry; + + nTotal += entry.nValue; + nCount++; + } + delete it; + return nTotal; +} + diff --git a/src/txdb-leveldb.h b/src/txdb-leveldb.h index ebaee79..d8a0299 100644 --- a/src/txdb-leveldb.h +++ b/src/txdb-leveldb.h @@ -236,6 +236,7 @@ public: bool WriteUtxo(const uint256& hash, unsigned int n, const CUtxoEntry& entry); bool EraseUtxo(const uint256& hash, unsigned int n); bool HaveUtxo(const uint256& hash, unsigned int n); + int64_t SumUtxoValues(int& nCount); private: bool LoadBlockIndexGuts(); diff --git a/src/version.cpp b/src/version.cpp index a5cd105..3c810e0 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -41,10 +41,10 @@ const std::string CLIENT_NAME("Cryptographic Triangles"); #endif #define BUILD_DESC_FROM_COMMIT(maj,min,rev,build,commit) \ - "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "" commit + "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "" commit #define BUILD_DESC_FROM_UNKNOWN(maj,min,rev,build) \ - "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "." DO_STRINGIZE(build) "" + "v" DO_STRINGIZE(maj) "." DO_STRINGIZE(min) "." DO_STRINGIZE(rev) "" #ifndef BUILD_DESC # ifdef GIT_COMMIT_ID