Compare commits

...

6 Commits

Author SHA1 Message Date
sami7777 a4da39f23c Update CI version to 5.1.9
Build All Platforms / build-windows-qt (push) Waiting to run
Build All Platforms / build-windows-daemon (push) Waiting to run
Build All Platforms / build-linux-qt (push) Waiting to run
Build All Platforms / build-linux-daemon (push) Waiting to run
Build All Platforms / build-macos (push) Waiting to run
Build All Platforms / release (push) Blocked by required conditions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:54:56 -07:00
sami7777 87bfc15712 Bump version to v5.1.9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:48:24 -07:00
sami7777 6353e9d5fa v5.1.9: Assumevalid fast sync + unlimited network buffers
Major sync performance overhaul:

- Assumevalid: skip FetchInputs/ConnectInputs for blocks below
  checkpoint (2,186,940). Only write txindex entries. Eliminates
  millions of LevelDB reads during initial sync.
- Skip SyncWithWallets during IBD with automatic post-IBD wallet
  rescan from genesis and SecureMsg chain scan.
- Skip wallet best-chain locator update during IBD so restarts
  trigger proper rescan.
- Remove send/receive buffer limits (were 1MB/5MB, now unlimited).
  The 1MB send buffer was the root cause of ~180 block stalls -
  ProcessMessages stops reading when nSendSize >= SendBufferSize().
- Reduce IBD pipeline batch from 500 to 100 blocks for faster
  re-requesting with near-instant block processing.
- Seed getblocks limit raised to 20000 during IBD (was 500).
- Faster message handler polling during IBD (10ms vs 100ms).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 17:41:08 -07:00
sami7777 14ce8cc2a7 Update CI version to 5.1.8
Build All Platforms / build-windows-qt (push) Waiting to run
Build All Platforms / build-windows-daemon (push) Waiting to run
Build All Platforms / build-linux-qt (push) Waiting to run
Build All Platforms / build-linux-daemon (push) Waiting to run
Build All Platforms / build-macos (push) Waiting to run
Build All Platforms / release (push) Blocked by required conditions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 03:51:12 -07:00
sami7777 d180b5870c Bump version to v5.1.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 03:45:55 -07:00
sami7777 596d4ab55c Enable real-time wallet sync and verbose progress during block download
Remove IBD guards on SyncWithWallets and SetBestChain so wallet
transactions appear as blocks are connected. Log every 500 blocks
during sync instead of every 10,000.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 02:58:45 -07:00
9 changed files with 241 additions and 75 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ on:
workflow_dispatch:
env:
VERSION: "5.1.7"
VERSION: "5.1.9"
jobs:
build-windows-qt:
+3 -3
View File
@@ -3,7 +3,7 @@
# Generated by qmake (3.1) (Qt 5.15.18)
# Project: triangles-qt.pro
# Template: app
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
#############################################################################
MAKEFILE = Makefile
@@ -156,7 +156,7 @@ Makefile: triangles-qt.pro C:/msys64/mingw64/share/qt5/mkspecs/win32-g++/qmake.c
C:/msys64/mingw64/lib/qtmain.prl \
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf \
src/qt/triangles.qrc
$(QMAKE) -o Makefile triangles-qt.pro
$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
C:/msys64/mingw64/share/qt5/mkspecs/features/spec_pre.prf:
C:/msys64/mingw64/share/qt5/mkspecs/qdevice.pri:
C:/msys64/mingw64/share/qt5/mkspecs/features/device_config.prf:
@@ -244,7 +244,7 @@ C:/msys64/mingw64/lib/qtmain.prl:
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf:
src/qt/triangles.qrc:
qmake: FORCE
@$(QMAKE) -o Makefile triangles-qt.pro
@$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
qmake_all: FORCE
+1 -1
View File
@@ -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 1
#define CLIENT_VERSION_REVISION 7
#define CLIENT_VERSION_REVISION 9
#define CLIENT_VERSION_BUILD 0
// Converts the parameter X to a string after macro replacement on X has been performed.
+2
View File
@@ -140,6 +140,7 @@ void Shutdown(void* parg)
if (fFirstThread)
{
fShutdown = true;
int64_t nDeferredWaitStart = GetTimeMillis();
while (true)
{
@@ -180,6 +181,7 @@ void Shutdown(void* parg)
fs::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
// DB is flushed and wallet saved - safe to force-exit if something hangs
NewThread(ExitTimeout, NULL);
MilliSleep(50);
printf("Triangles exited\n\n");
+118 -32
View File
@@ -1639,6 +1639,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
if (!CheckBlock(!fJustCheck, !fJustCheck, false))
return false;
// Determine if this block is covered by the hardcoded checkpoint.
// Below checkpoint: skip all input validation, FetchInputs, ConnectInputs,
// and wallet sync. The checkpoint hash guarantees chain integrity for these blocks.
bool fAssumeValid = (pindex->nHeight <= Checkpoints::GetTotalBlocksEstimate());
bool fIsInitialDownload = IsInitialBlockDownload();
//// issue here: it doesn't know the version
unsigned int nTxPos;
if (fJustCheck)
@@ -1658,6 +1664,20 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
{
uint256 hashTx = tx.GetHash();
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
if (!fJustCheck)
nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
// Fast path: below checkpoint, skip all input validation and spent-tracking.
// Just record where each transaction lives on disk (txindex).
if (fAssumeValid)
{
mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
continue;
}
// Full validation path (above checkpoint)
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
// If such overwrites are allowed, coinbases and transactions depending upon those
@@ -1681,10 +1701,6 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("ConnectBlock() : too many sigops"));
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
if (!fJustCheck)
nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
MapPrevTx mapInputs;
if (tx.IsCoinBase())
nValueOut += tx.GetValueOut();
@@ -1717,20 +1733,18 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
}
if (IsProofOfWork() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
if (!fAssumeValid)
{
int64_t nReward = GetProofOfWorkReward(nFees);
// Check coinbase reward
if (vtx[0].GetValueOut() > nReward)
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%"PRId64" vs calculated=%"PRId64")",
vtx[0].GetValueOut(),
nReward));
}
if (IsProofOfStake())
if (IsProofOfWork())
{
// Skip expensive coin age calculation and reward validation for blocks
// covered by the hardcoded checkpoint. The checkpoint guarantees chain integrity.
if (pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
int64_t nReward = GetProofOfWorkReward(nFees);
// Check coinbase reward
if (vtx[0].GetValueOut() > nReward)
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%"PRId64" vs calculated=%"PRId64")",
vtx[0].GetValueOut(),
nReward));
}
if (IsProofOfStake())
{
// triangles: coin stake tx earns reward instead of paying fee
uint64_t nCoinAge;
@@ -1760,8 +1774,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
return error("ConnectBlock() : UpdateTxIndex failed");
}
// Update address index
if (fAddressIndex)
// Update address index (skip during IBD - will be rebuilt on next start with -reindex)
if (fAddressIndex && !fIsInitialDownload)
{
for (unsigned int i = 0; i < vtx.size(); i++)
{
@@ -1834,9 +1848,9 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
return error("ConnectBlock() : WriteBlockIndex failed");
}
// Watch for transactions paying to me
// Skip during initial block download - wallet will rescan on next normal startup
if (!IsInitialBlockDownload())
// Skip wallet sync during IBD - a full wallet rescan runs when IBD completes.
// This eliminates millions of per-transaction wallet lookups during sync.
if (!fIsInitialDownload)
{
BOOST_FOREACH(CTransaction& tx, vtx)
SyncWithWallets(tx, this, true);
@@ -2038,7 +2052,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
}
}
// Update best block in wallet (so we can detect restored wallets)
// Update best block in wallet (so we can detect restored wallets).
// During IBD, skip this so the wallet knows it needs rescanning on restart.
bool fIsInitialDownload = IsInitialBlockDownload();
if (!fIsInitialDownload)
{
@@ -2057,7 +2072,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
if (nBestHeight % 10000 == 0 || nBestHeight > 2186900)
// Log every 5000 blocks during sync, every block once caught up
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
printf("SetBestChain: new best=%s height=%d trust=%s blocktrust=%"PRId64" date=%s\n",
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
CBigNum(nBestChainTrust).ToString().c_str(),
@@ -2108,6 +2124,40 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
pNotificationQueue->Push(strBlockEvent);
}
// Detect IBD-to-synced transition and trigger deferred work:
// wallet rescan (since SyncWithWallets was skipped) and smsg chain scan.
{
static bool fWasInitialDownload = true;
if (fWasInitialDownload && !fIsInitialDownload)
{
printf("*** Initial block download complete at height %d ***\n", nBestHeight);
// Update wallet best chain locator now that IBD is done
const CBlockLocator locator(pindexBest);
::SetBestChain(locator);
// Wallet rescan: SyncWithWallets was skipped during IBD, so scan
// the entire chain to pick up all wallet transactions.
if (pwalletMain)
{
printf("Starting post-IBD wallet rescan from genesis...\n");
uiInterface.InitMessage(_("Rescanning wallet..."));
int nFound = pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
printf("Post-IBD wallet rescan complete: %d transactions found\n", nFound);
}
// Secure messaging: scan chain for public keys needed to decrypt messages
if (fSecMsgEnabled)
{
printf("Starting post-IBD secure message chain scan...\n");
uiInterface.InitMessage(_("Scanning for secure messages..."));
SecureMsgScanBlockChain();
printf("Post-IBD secure message chain scan complete\n");
}
}
fWasInitialDownload = fIsInitialDownload;
}
return true;
}
@@ -2604,8 +2654,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
mapOrphanBlocksByPrev.erase(hashPrev);
}
if (nBestHeight % 10000 == 0 || nBestHeight > 2186900)
printf("ProcessBlock: ACCEPTED\n");
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
printf("ProcessBlock: ACCEPTED block %d\n", nBestHeight);
// triangles: if responsible for sync-checkpoint send it
if (pfrom && !CSyncCheckpoint::strMasterPrivKey.empty())
@@ -3217,13 +3267,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
}
}
// Ask the first connected node for block updates
// Ask connected nodes for block updates
// During IBD, always request blocks from any valid peer (critical for reconnection)
static int nAskedForBlocks = 0;
if (!pfrom->fClient && !pfrom->fOneShot &&
(pfrom->nStartingHeight > (nBestHeight - 144)) &&
(pfrom->nVersion < NOBLKS_VERSION_START ||
pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
(IsInitialBlockDownload() || nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
pfrom->PushGetBlocks(pindexBest, uint256(0));
@@ -3470,7 +3521,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
int nLimit = 500;
int nLimit = IsInitialBlockDownload() ? 20000 : 500;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
@@ -3680,19 +3731,35 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
vRecv >> block;
uint256 hashBlock = block.GetHash();
printf("received block %s\n", hashBlock.ToString().substr(0,20).c_str());
if (!IsInitialBlockDownload())
printf("received block %s\n", hashBlock.ToString().substr(0,20).c_str());
// block.print();
CInv inv(MSG_BLOCK, hashBlock);
pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, &block))
{
mapAlreadyAskedFor.erase(inv);
// During IBD, proactively request more blocks to keep the pipeline full.
// With assumevalid, blocks process near-instantly, so request aggressively.
if (IsInitialBlockDownload())
{
static int nBlocksSinceRequest = 0;
if (++nBlocksSinceRequest >= 100)
{
nBlocksSinceRequest = 0;
pfrom->pindexLastGetBlocksBegin = NULL; // clear dedup filter
pfrom->PushGetBlocks(pindexBest, uint256(0));
}
}
}
if (block.nDoS)
pfrom->Misbehaving(block.nDoS);
if (fSecMsgEnabled)
if (fSecMsgEnabled && !IsInitialBlockDownload())
SecureMsgScanBlock(block);
}
@@ -4126,6 +4193,25 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->PushMessage("inv", vInv);
//
// Stall detection: if IBD and no new blocks for 30 seconds, re-request
//
if (IsInitialBlockDownload() && !pto->fClient)
{
static int64_t nLastBlockReceived = 0;
static int nLastHeight = 0;
if (nBestHeight > nLastHeight) {
nLastHeight = nBestHeight;
nLastBlockReceived = GetTime();
} else if (nLastBlockReceived > 0 && GetTime() - nLastBlockReceived > 5) {
printf("IBD stall detected at height %d, re-requesting blocks\n", nBestHeight);
// Clear dedup filter so the request actually sends
pto->pindexLastGetBlocksBegin = NULL;
pto->PushGetBlocks(pindexBest, uint256(0));
nLastBlockReceived = GetTime(); // reset timer
}
}
//
// Message: getdata
//
+47 -20
View File
@@ -6,6 +6,7 @@
#include "irc.h"
#include "db.h"
#include "net.h"
#include "main.h"
#include "init.h"
#include "strlcpy.h"
#include "addrman.h"
@@ -889,7 +890,7 @@ void ThreadSocketHandler2(void* parg)
//
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000; // frequency to poll pnode->vSend
timeout.tv_usec = IsInitialBlockDownload() ? 10000 : 50000; // faster polling during IBD
fd_set fdsetRecv;
fd_set fdsetSend;
@@ -1574,24 +1575,29 @@ void ThreadOpenConnections2(void* parg)
if (fShutdown)
return;
// Add seed nodes if IRC isn't working
if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
// Add hardcoded seed nodes when we have no connections.
// Original check (addrman.size()==0) was too conservative - stale entries
// in peers.dat would prevent fallback to working hardcoded IPs forever.
{
std::vector<CAddress> vAdd;
for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
{
// It'll only connect to one or two seed nodes because once it connects,
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
const int64_t nOneWeek = 7*24*60*60;
struct in_addr ip;
memcpy(&ip, &pnSeed[i], sizeof(ip));
CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
vAdd.push_back(addr);
LOCK(cs_vNodes);
bool fNoOutbound = true;
BOOST_FOREACH(CNode* pnode, vNodes) {
if (!pnode->fInbound) { fNoOutbound = false; break; }
}
if (fNoOutbound && (GetTime() - nStart > 30) && !fTestNet)
{
std::vector<CAddress> vAdd;
for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
{
struct in_addr ip;
memcpy(&ip, &pnSeed[i], sizeof(ip));
CAddress addr(CService(ip, GetDefaultPort()));
addr.nTime = GetTime() - GetRand(60*60); // seen recently
vAdd.push_back(addr);
}
addrman.Add(vAdd, CNetAddr("127.0.0.1"));
printf("No outbound connections after 30s, added %d hardcoded seeds\n", (int)vAdd.size());
}
addrman.Add(vAdd, CNetAddr("127.0.0.1"));
}
//
@@ -1809,6 +1815,7 @@ void ThreadMessageHandler2(void* parg)
{
printf("ThreadMessageHandler started\n");
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
bool fWasBoosted = false;
while (!fShutdown)
{
vector<CNode*> vNodesCopy;
@@ -1851,11 +1858,21 @@ void ThreadMessageHandler2(void* parg)
pnode->Release();
}
// Boost thread priority during IBD, restore when caught up
if (IsInitialBlockDownload() && !fWasBoosted) {
SetThreadPriority(THREAD_PRIORITY_NORMAL);
fWasBoosted = true;
} else if (!IsInitialBlockDownload() && fWasBoosted) {
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
fWasBoosted = false;
}
// Wait and allow messages to bunch up.
// During IBD, use a shorter sleep to maximize block processing throughput.
// Reduce vnThreadsRunning so StopNode has permission to exit while
// we're sleeping, but we must always check fShutdown after doing this.
vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
MilliSleep(100);
MilliSleep(IsInitialBlockDownload() ? 10 : 100);
if (fRequestShutdown)
StartShutdown();
vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
@@ -2149,8 +2166,18 @@ bool StopNode()
if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
if (vnThreadsRunning[THREAD_STAKE_MINER] > 0) printf("ThreadStakeMiner still running\n");
while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0)
MilliSleep(20);
{
int64_t nWaitStart = GetTime();
while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0)
{
if (GetTime() - nWaitStart > 10)
{
printf("Timed out waiting for message/RPC threads to stop\n");
break;
}
MilliSleep(20);
}
}
MilliSleep(50);
DumpAddresses();
return true;
+9 -4
View File
@@ -22,12 +22,13 @@
class CRequestTracker;
class CNode;
class CBlockIndex;
bool IsInitialBlockDownload();
extern int nBestHeight;
inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
inline unsigned int ReceiveFloodSize() { return (unsigned int)-1; }
inline unsigned int SendBufferSize() { return (unsigned int)-1; }
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine);
@@ -429,8 +430,12 @@ public:
nNow = std::max(nNow, nLastTime);
nLastTime = nNow;
// Each retry is 2 minutes after the last
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
// During IBD, request immediately (no 2-minute retry delay)
// Normal operation: each retry is 2 minutes after the last
if (nRequestTime > 0 && IsInitialBlockDownload())
nRequestTime = nNow;
else
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
mapAskFor.insert(std::make_pair(nRequestTime, inv));
}
+3 -1
View File
@@ -63,7 +63,9 @@ void ClientModel::updateTimer()
int newNumBlocks = getNumBlocks();
int newNumBlocksOfPeers = getNumBlocksOfPeers();
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
// Always emit during IBD so the speed/ETA display stays live
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers
|| newNumBlocks < newNumBlocksOfPeers)
{
cachedNumBlocks = newNumBlocks;
cachedNumBlocksOfPeers = newNumBlocksOfPeers;
+57 -13
View File
@@ -751,24 +751,57 @@ void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
QString tooltip;
QString importText;
importText = tr("Synchronizing with network...");
if(count < nTotalBlocks)
{
// Calculate blocks/sec - only update rate when new blocks arrive
static int lastCount = 0;
static qint64 lastRateTime = 0;
static float blocksPerSec = 0.0f;
qint64 now = QDateTime::currentMSecsSinceEpoch();
if (count > lastCount) {
// New blocks arrived - recalculate speed
if (lastRateTime > 0) {
float elapsed = (now - lastRateTime) / 1000.0f;
if (elapsed > 0.1f) {
float instantRate = (count - lastCount) / elapsed;
blocksPerSec = (blocksPerSec < 0.1f) ? instantRate : (blocksPerSec * 0.7f + instantRate * 0.3f);
}
}
lastCount = count;
lastRateTime = now;
} else if (lastRateTime > 0 && (now - lastRateTime) > 10000) {
// No blocks for 10+ seconds - show 0
blocksPerSec = 0.0f;
}
int nRemainingBlocks = nTotalBlocks - count;
float nPercentageDone = count / (nTotalBlocks * 0.01f);
progressBarLabel->setText(importText);
// Build informative status text
QString speedText;
if (blocksPerSec >= 1.0f) {
int etaSeconds = (int)(nRemainingBlocks / blocksPerSec);
QString etaStr;
if (etaSeconds < 60)
etaStr = tr("%n sec", "", etaSeconds);
else if (etaSeconds < 3600)
etaStr = tr("%n min", "", etaSeconds / 60);
else
etaStr = tr("%1h %2m").arg(etaSeconds / 3600).arg((etaSeconds % 3600) / 60);
speedText = tr("Syncing: %1 blk/s ~%2 remaining").arg(blocksPerSec, 0, 'f', 1).arg(etaStr);
} else {
speedText = tr("Synchronizing with network...");
}
progressBarLabel->setText(speedText);
progressBarLabel->setVisible(true);
progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
progressBar->setFormat(tr("Block %1 / %2 (%3%)").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2));
progressBar->setMaximum(nTotalBlocks);
progressBar->setValue(count);
progressBar->setVisible(true);
ui->label_blocks->setText(tr("%n blocks", "", count));
ui->label_blocks->setVisible(true);
ui->label_blocks->setVisible(false);
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
}
else
{
@@ -871,16 +904,27 @@ void TrianglesGUI::changeEvent(QEvent *e)
void TrianglesGUI::closeEvent(QCloseEvent *event)
{
#ifndef Q_OS_MAC // Ignored on Mac
if(clientModel)
{
#ifndef Q_OS_MAC // Ignored on Mac
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
!clientModel->getOptionsModel()->getMinimizeOnClose())
if(clientModel->getOptionsModel()->getMinimizeOnClose())
{
QApplication::quit();
// Minimize to taskbar instead of closing
QMainWindow::showMinimized();
event->ignore();
return;
}
if(clientModel->getOptionsModel()->getMinimizeToTray() && trayIcon)
{
// Hide to system tray instead of closing
hide();
event->ignore();
return;
}
#endif
}
#endif
// Actually closing - quit the application
QApplication::quit();
QMainWindow::closeEvent(event);
}