2ba0ecf428
Migration from boost to std-library equivalents and removal of unreachable code paths. Touches infrastructure only — no consensus rule or wallet serialization changes. Dead code removed: - IRC bootstrap (irc.cpp/h, 417 lines): orphan from pre-Tor era, no callers. - Alert system (alert.cpp/h + sendalert RPC + Qt UI signal, ~500 lines): retired post-V5 fork; old peers' alert messages now hit the unknown-cmd default branch, logged + ignored. - Legacy P2P handlers in main.cpp: "checkpoint" (already a no-op stub since V5 fork master-key removal), "checkorder"/"reply" (2010-era Receive-by-IP feature), plus their unused supporting structures (CRequestTracker, PushRequest overloads, mapRequests/cs_mapRequests, mapReuseKey). - Unreachable RPCs clearwallettransactions and scanforalltxns (~175 lines): defined in rpcwallet.cpp but never registered in the dispatch table. - Stale -alertnotify CLI help text (option was advertised but never wired). boost::filesystem -> std::filesystem (C++17): - 30 source files, 5 headers. namespace fs = boost::filesystem swapped to namespace fs = std::filesystem; boost::filesystem::ifstream/ofstream replaced with std::ifstream/ofstream (path-aware in C++17); fs::system_complete -> fs::absolute; boost::filesystem::filesystem_error -> std::filesystem::filesystem_error. - Build system: dropped Boost::filesystem from link libs and Boost components; PCH includes updated. - Added explicit <filesystem> includes where types were previously available only transitively (db.h, rpcblockchain.cpp). boost::thread -> std::thread (12 files): - sync.h CCriticalSection/CWaitableCriticalSection now alias std::recursive_mutex/std::mutex. boost::unique_lock and boost::condition_variable / boost::mutex::scoped_lock swapped to std equivalents; sync.cpp boost::thread_specific_ptr -> thread_local std::unique_ptr. - init.cpp boost::thread_group rewritten as std::vector<std::thread> with manual join loop. boost::thread::hardware_concurrency -> std::thread::hardware_concurrency. - main.cpp/wallet.cpp -blocknotify/-walletnotify shell-out threads now use std::thread(...).detach() — fixes a latent bug where modern boost::thread destructor would call std::terminate on the joinable thread. - util.cpp NewThread now catches std::system_error. - No interruption_point/interrupt usage anywhere — pure mechanical swap. boost::chrono / boost::posix_time -> std::chrono (3 of 5 files): - util.h: MilliSleep, GetTimeMillis, GetTimeMicros rewritten on std::chrono (system_clock for epoch math, sleep_for for delays). - snapshotnet.cpp: sleep_for swapped. - DoS_tests.cpp: timing harness uses steady_clock. - Skipped: rpcdump.cpp (boost::posix_time::time_input_facet has no clean std::get_time equivalent) and qt/qtipcserver.cpp (locked to boost::posix_time by boost::interprocess::message_queue::timed_receive). Other housekeeping: - Dropped unnecessary "using namespace boost;" from txdb-leveldb.cpp, txdb-rocksdb.cpp, walletdb.cpp, db.cpp (verified no unqualified boost names in those TUs). - Removed unused extern declaration for clearwallettransactions. Build fixes for non-unity builds on MinGW64/GCC 15: - net.cpp: dropped stale #include "irc.h". - addrman.cpp + main.cpp: explicit <cmath> include for sqrt/pow (was arriving transitively via boost headers). - rpcblockchain.cpp + init.cpp: defensive #undef STRICT/ADVISORY/PERMISSIVE since windows.h macros collide with the Checkpoints:: enum values when std headers reorder include flow. - tor_embed_hooks.cpp: triangles_tor_check_interrupted now polls fShutdown instead of boost::this_thread::interruption_requested (we never used boost interruption — the hook was always effectively a no-op). - snapshotnet.cpp: fs::remove error handle uses std::error_code. - serialize.h: added <ios> for std::ios::badbit/failbit (was relying on transitive include via boost). Note: unity builds currently fail on this branch due to std::byte (C++17) colliding with COM 'byte' typedef from shlobj.h when 'using namespace std;' from earlier files in the unity slice leaks into util.cpp's parse of shlobj.h. Build with -DENABLE_UNITY_BUILD=OFF (the default). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
286 lines
12 KiB
C++
286 lines
12 KiB
C++
#include "transactiondesc.h"
|
|
|
|
#include "guiutil.h"
|
|
#include "trianglesunits.h"
|
|
|
|
#include "main.h"
|
|
#include "wallet.h"
|
|
#include "txdb.h"
|
|
#include "ui_interface.h"
|
|
#include "base58.h"
|
|
|
|
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
|
|
{
|
|
if (!wtx.IsFinal())
|
|
{
|
|
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
|
|
return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime);
|
|
else
|
|
return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime));
|
|
}
|
|
else
|
|
{
|
|
int nDepth = wtx.GetDepthInMainChain();
|
|
if (nDepth < 0)
|
|
return tr("conflicted");
|
|
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
|
|
return tr("%1/offline").arg(nDepth);
|
|
else if (nDepth < 10)
|
|
return tr("%1/unconfirmed").arg(nDepth);
|
|
else
|
|
return tr("%1 confirmations").arg(nDepth);
|
|
}
|
|
}
|
|
|
|
QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
|
{
|
|
QString strHTML;
|
|
|
|
{
|
|
LOCK(wallet->cs_wallet);
|
|
strHTML.reserve(4000);
|
|
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
|
|
|
|
int64_t nTime = wtx.GetTxTime();
|
|
int64_t nCredit = wtx.GetCredit();
|
|
int64_t nDebit = wtx.GetDebit();
|
|
int64_t nNet = nCredit - nDebit;
|
|
|
|
strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx);
|
|
int nRequests = wtx.GetRequestCount();
|
|
if (nRequests != -1)
|
|
{
|
|
if (nRequests == 0)
|
|
strHTML += tr(", has not been successfully broadcast yet");
|
|
else if (nRequests > 0)
|
|
strHTML += tr(", broadcast through %n node(s)", "", nRequests);
|
|
}
|
|
strHTML += "<br>";
|
|
|
|
strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>";
|
|
|
|
//
|
|
// From
|
|
//
|
|
if (wtx.IsCoinBase() || wtx.IsCoinStake())
|
|
{
|
|
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
|
|
}
|
|
else if (wtx.mapValue.count("from") && !wtx.mapValue["from"].empty())
|
|
{
|
|
// Online transaction
|
|
strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>";
|
|
}
|
|
else
|
|
{
|
|
// Offline transaction
|
|
if (nNet > 0)
|
|
{
|
|
// Credit
|
|
for (const CTxOut& txout : wtx.vout)
|
|
{
|
|
if (wallet->IsMine(txout))
|
|
{
|
|
CTxDestination address;
|
|
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
|
|
{
|
|
if (wallet->mapAddressBook.count(address))
|
|
{
|
|
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
|
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
|
strHTML += GUIUtil::HtmlEscape(CTrianglesAddress(address).ToString());
|
|
if (!wallet->mapAddressBook[address].empty())
|
|
strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")";
|
|
else
|
|
strHTML += " (" + tr("own address") + ")";
|
|
strHTML += "<br>";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// To
|
|
//
|
|
if (wtx.mapValue.count("to") && !wtx.mapValue["to"].empty())
|
|
{
|
|
// Online transaction
|
|
std::string strAddress = wtx.mapValue["to"];
|
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
|
CTxDestination dest = CTrianglesAddress(strAddress).Get();
|
|
if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty())
|
|
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " ";
|
|
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
|
|
}
|
|
|
|
//
|
|
// Amount
|
|
//
|
|
if (wtx.IsCoinBase() && nCredit == 0)
|
|
{
|
|
//
|
|
// Coinbase
|
|
//
|
|
int64_t nUnmatured = 0;
|
|
for (const CTxOut& txout : wtx.vout)
|
|
nUnmatured += wallet->GetCredit(txout);
|
|
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
|
if (wtx.IsInMainChain())
|
|
strHTML += TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")";
|
|
else
|
|
strHTML += "(" + tr("not accepted") + ")";
|
|
strHTML += "<br>";
|
|
}
|
|
else if (nNet > 0)
|
|
{
|
|
//
|
|
// Credit
|
|
//
|
|
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, nNet) + "<br>";
|
|
}
|
|
else
|
|
{
|
|
bool fAllFromMe = true;
|
|
for (const CTxIn& txin : wtx.vin)
|
|
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
|
|
|
|
bool fAllToMe = true;
|
|
for (const CTxOut& txout : wtx.vout)
|
|
fAllToMe = fAllToMe && wallet->IsMine(txout);
|
|
|
|
if (fAllFromMe)
|
|
{
|
|
//
|
|
// Debit
|
|
//
|
|
for (const CTxOut& txout : wtx.vout)
|
|
{
|
|
if (wallet->IsMine(txout))
|
|
continue;
|
|
|
|
if (!wtx.mapValue.count("to") || wtx.mapValue["to"].empty())
|
|
{
|
|
// Offline transaction
|
|
CTxDestination address;
|
|
if (ExtractDestination(txout.scriptPubKey, address))
|
|
{
|
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
|
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
|
|
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
|
|
strHTML += GUIUtil::HtmlEscape(CTrianglesAddress(address).ToString());
|
|
strHTML += "<br>";
|
|
}
|
|
}
|
|
|
|
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -txout.nValue) + "<br>";
|
|
}
|
|
|
|
if (fAllToMe)
|
|
{
|
|
// Payment to self
|
|
int64_t nChange = wtx.GetChange();
|
|
int64_t nValue = nCredit - nChange;
|
|
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -nValue) + "<br>";
|
|
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, nValue) + "<br>";
|
|
}
|
|
|
|
int64_t nTxFee = nDebit - wtx.GetValueOut();
|
|
if (nTxFee > 0)
|
|
strHTML += "<b>" + tr("Transaction fee") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -nTxFee) + "<br>";
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Mixed debit transaction
|
|
//
|
|
for (const CTxIn& txin : wtx.vin)
|
|
if (wallet->IsMine(txin))
|
|
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -wallet->GetDebit(txin)) + "<br>";
|
|
for (const CTxOut& txout : wtx.vout)
|
|
if (wallet->IsMine(txout))
|
|
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, wallet->GetCredit(txout)) + "<br>";
|
|
}
|
|
}
|
|
|
|
strHTML += "<b>" + tr("Net amount") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, nNet, true) + "<br>";
|
|
|
|
//
|
|
// Message
|
|
//
|
|
if (wtx.mapValue.count("message") && !wtx.mapValue["message"].empty())
|
|
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>";
|
|
if (wtx.mapValue.count("comment") && !wtx.mapValue["comment"].empty())
|
|
strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
|
|
|
|
char cbuf[256];
|
|
for (int k = 0; k < wtx.vout.size(); ++k)
|
|
{
|
|
snprintf(cbuf, sizeof(cbuf), "n_%d", k);
|
|
if (wtx.mapValue.count(cbuf) && !wtx.mapValue[cbuf].empty())
|
|
strHTML += "<br><b>" + tr(cbuf) + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue[cbuf], true) + "<br>";
|
|
}
|
|
|
|
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>";
|
|
|
|
if (wtx.IsCoinBase() || wtx.IsCoinStake())
|
|
strHTML += "<br>" + tr("Generated coins must mature 7 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
|
|
|
|
//
|
|
// Debug view
|
|
//
|
|
if (fDebug)
|
|
{
|
|
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
|
for (const CTxIn& txin : wtx.vin)
|
|
if(wallet->IsMine(txin))
|
|
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -wallet->GetDebit(txin)) + "<br>";
|
|
for (const CTxOut& txout : wtx.vout)
|
|
if(wallet->IsMine(txout))
|
|
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, wallet->GetCredit(txout)) + "<br>";
|
|
|
|
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
|
|
strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true);
|
|
|
|
auto txdb_holder = MakeChainDB("r"); CTxDBBase& txdb = *txdb_holder; // To fetch source txouts
|
|
|
|
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
|
|
strHTML += "<ul>";
|
|
|
|
{
|
|
LOCK(wallet->cs_wallet);
|
|
for (const CTxIn& txin : wtx.vin)
|
|
{
|
|
COutPoint prevout = txin.prevout;
|
|
|
|
CTransaction prev;
|
|
if(txdb.ReadDiskTx(prevout.hash, prev))
|
|
{
|
|
if (prevout.n < prev.vout.size())
|
|
{
|
|
strHTML += "<li>";
|
|
const CTxOut &vout = prev.vout[prevout.n];
|
|
CTxDestination address;
|
|
if (ExtractDestination(vout.scriptPubKey, address))
|
|
{
|
|
if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty())
|
|
strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " ";
|
|
strHTML += QString::fromStdString(CTrianglesAddress(address).ToString());
|
|
}
|
|
strHTML = strHTML + " " + tr("Amount") + "=" + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, vout.nValue);
|
|
strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
strHTML += "</ul>";
|
|
}
|
|
|
|
strHTML += "</font></html>";
|
|
}
|
|
return strHTML;
|
|
}
|