diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp index 210649edb..5112f961c 100644 --- a/alethzero/DownloadView.cpp +++ b/alethzero/DownloadView.cpp @@ -30,29 +30,95 @@ using namespace std; using namespace dev; using namespace dev::eth; -DownloadView::DownloadView(QWidget* _p): QWidget(_p) +SyncView::SyncView(QWidget* _p): QWidget(_p) { } -void DownloadView::paintEvent(QPaintEvent*) +void SyncView::paintEvent(QPaintEvent*) { QPainter p(this); - p.fillRect(rect(), Qt::white); - if (!m_man || m_man->chainEmpty() || !m_man->subCount()) + + if (!m_client) + return; + + DownloadMan const* man = m_client->downloadMan(); + BlockQueueStatus bqs = m_client->blockQueueStatus(); + SyncStatus sync = m_client->syncStatus(); + + unsigned syncFrom = m_client->numberFromHash(PendingBlockHash); + unsigned syncImported = syncFrom; + unsigned syncImporting = syncImported + bqs.importing; + unsigned syncVerified = syncImporting + bqs.verified; + unsigned syncVerifying = syncVerified + bqs.verifying; + unsigned syncUnverified = syncVerifying + bqs.unverified; + unsigned syncUnknown = syncUnverified + bqs.unknown; + + // best effort guess. assumes there's no forks. + unsigned downloadFrom = m_client->numberFromHash(m_client->isKnown(man->firstBlock()) ? man->firstBlock() : PendingBlockHash); + unsigned downloadCount = sync.blocksTotal; + DownloadMan::Overview overview = man->overview(); + unsigned downloadDone = downloadFrom + overview.total; + unsigned downloadFlank = downloadFrom + overview.firstIncomplete; + unsigned downloadPoint = downloadFrom + overview.lastComplete; + + unsigned hashFrom = sync.state == SyncState::Hashes ? m_client->numberFromHash(PendingBlockHash) : downloadFrom; + unsigned hashCount = sync.state == SyncState::Hashes ? sync.hashesTotal : downloadCount; + unsigned hashDone = hashFrom + (sync.state == SyncState::Hashes ? sync.hashesReceived : hashCount); + + m_lastFrom = min(syncFrom, m_lastFrom); + unsigned from = min(min(hashFrom, downloadFrom), min(syncFrom, m_lastFrom)); + unsigned count = max(hashFrom + hashCount, downloadFrom + downloadCount) - from; + m_lastFrom = (m_lastFrom * 95 + syncFrom) / 100; + + if (!count) + { + m_lastFrom = (unsigned)-1; return; + } + + cnote << "Range " << from << "-" << (from + count); + auto r = [&](unsigned u) { + return toString((u - from) * 100 / count) + "%"; + }; + + if (count) + { + cnote << "Hashes:" << r(hashDone) << " Blocks:" << r(downloadFlank) << r(downloadDone) << r(downloadPoint); + cnote << "Importing:" << r(syncFrom) << r(syncImported) << r(syncImporting) << r(syncVerified) << r(syncVerifying) << r(syncUnverified) << r(syncUnknown); + } + + if (!man || man->chainEmpty() || !man->subCount()) + return; + + float s = min(rect().width(), rect().height()); + QPen pen; + pen.setCapStyle(Qt::FlatCap); + pen.setWidthF(s / 10); + p.setPen(pen); + auto middle = [&](float x) { + return QRectF(s / 2 - s / 2 * x, 0 + s / 2 - s / 2 * x, s * x, s * x); + }; + + auto toArc = [&](unsigned x) { + return (x - from) * -5760.f / count; + }; + const float arcFrom = 90 * 16.f; + p.drawArc(middle(0.5f), arcFrom, toArc(downloadDone)); + p.drawPie(middle(0.2f), arcFrom, toArc(hashDone)); + return; double ratio = (double)rect().width() / rect().height(); if (ratio < 1) ratio = 1 / ratio; - double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(m_man->chainSize() / ratio))); + double n = min(16.0, min(rect().width(), rect().height()) / ceil(sqrt(man->chainSize() / ratio))); // QSizeF area(rect().width() / floor(rect().width() / n), rect().height() / floor(rect().height() / n)); QSizeF area(n, n); QPointF pos(0, 0); - auto bg = m_man->blocksGot(); - unsigned subCount = m_man->subCount(); + auto bg = man->blocksGot(); + unsigned subCount = man->subCount(); if (subCount == 0) return; unsigned dh = 360 / subCount; @@ -64,7 +130,7 @@ void DownloadView::paintEvent(QPaintEvent*) else { unsigned h = 0; - m_man->foreachSub([&](DownloadSub const& sub) + man->foreachSub([&](DownloadSub const& sub) { if (sub.askedContains(i)) s = h; diff --git a/alethzero/DownloadView.h b/alethzero/DownloadView.h index d0fc445f8..9ee2428b2 100644 --- a/alethzero/DownloadView.h +++ b/alethzero/DownloadView.h @@ -32,21 +32,23 @@ #endif namespace dev { namespace eth { -class DownloadMan; +class Client; }} -class DownloadView: public QWidget +class SyncView: public QWidget { Q_OBJECT public: - DownloadView(QWidget* _p = nullptr); + SyncView(QWidget* _p = nullptr); - void setDownloadMan(dev::eth::DownloadMan const* _man) { m_man = _man; } + void setEthereum(dev::eth::Client const* _c) { m_client = _c; } protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::DownloadMan const* m_man = nullptr; + dev::eth::Client const* m_client = nullptr; + + unsigned m_lastFrom = (unsigned)-1; }; diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b2e3a9a29..37ff7f66c 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -1149,7 +1149,7 @@ font-size: 14pt 0 - + @@ -1814,7 +1814,7 @@ font-size: 14pt 1 - DownloadView + SyncView QWidget
DownloadView.h
1 diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index bc569c5cf..ba4bec863 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1993,12 +1993,12 @@ void Main::on_net_triggered() web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); web3()->startNetwork(); - ui->downloadView->setDownloadMan(ethereum()->downloadMan()); + ui->downloadView->setEthereum(ethereum()); ui->enode->setText(QString::fromStdString(web3()->enode())); } else { - ui->downloadView->setDownloadMan(nullptr); + ui->downloadView->setEthereum(nullptr); writeSettings(); web3()->stopNetwork(); } diff --git a/exp/main.cpp b/exp/main.cpp index 1db9b4267..88608f8cf 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -135,7 +135,7 @@ int main() DownloadSub s0(man); DownloadSub s1(man); DownloadSub s2(man); - man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)})); + man.resetToChain(h256s({u256(0), u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8)}), 0); assert((s0.nextFetch(2) == h256Set{(u256)7, (u256)8})); assert((s1.nextFetch(2) == h256Set{(u256)5, (u256)6})); assert((s2.nextFetch(2) == h256Set{(u256)3, (u256)4})); diff --git a/libdevcore/RangeMask.h b/libdevcore/RangeMask.h index eccc8305d..6c32517f5 100644 --- a/libdevcore/RangeMask.h +++ b/libdevcore/RangeMask.h @@ -200,6 +200,20 @@ public: return c; } + size_t firstOut() const + { + if (m_ranges.empty() || !m_ranges.count(m_all.first)) + return m_all.first; + return m_ranges.at(m_all.first); + } + + size_t lastIn() const + { + if (m_ranges.empty()) + return m_all.first; + return m_ranges.rbegin()->second - 1; + } + private: /// The ground range. UnsignedRange m_all; diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index e22f10880..5dd1a97cb 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -80,7 +80,7 @@ DownloadMan& BlockChainSync::downloadMan() void BlockChainSync::abortSync() { - downloadMan().resetToChain(h256s()); + downloadMan().reset(); } void BlockChainSync::onPeerStatus(std::shared_ptr _peer) diff --git a/libethereum/DownloadMan.cpp b/libethereum/DownloadMan.cpp index 5e68e3c49..a9d353292 100644 --- a/libethereum/DownloadMan.cpp +++ b/libethereum/DownloadMan.cpp @@ -24,6 +24,16 @@ using namespace std; using namespace dev; using namespace dev::eth; +DownloadMan::Overview DownloadMan::overview() const +{ + ReadGuard l(m_lock); + Overview ret; + ret.firstIncomplete = m_blocksGot.firstOut(); + ret.lastComplete = ret.lastStarted = m_blocksGot.lastIn();// TODO: lastStarted properly + ret.total = m_blocksGot.size(); + return ret; +} + DownloadSub::DownloadSub(DownloadMan& _man): m_man(&_man) { WriteGuard l(m_man->x_subs); diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h index ac99e1d36..b697d87ae 100644 --- a/libethereum/DownloadMan.h +++ b/libethereum/DownloadMan.h @@ -82,6 +82,14 @@ class DownloadMan friend class DownloadSub; public: + struct Overview + { + size_t total; + size_t firstIncomplete; + size_t lastComplete; + size_t lastStarted; + }; + ~DownloadMan() { for (auto i: m_subs) @@ -97,11 +105,9 @@ public: void resetToChain(h256s const& _chain) { - { - ReadGuard l(x_subs); + DEV_READ_GUARDED(x_subs) for (auto i: m_subs) i->resetFetch(); - } WriteGuard l(m_lock); m_chain.clear(); m_chain.reserve(_chain.size()); @@ -112,11 +118,9 @@ public: void reset() { - { - ReadGuard l(x_subs); + DEV_READ_GUARDED(x_subs) for (auto i: m_subs) i->resetFetch(); - } WriteGuard l(m_lock); m_chain.clear(); m_blocksGot.reset(); @@ -127,11 +131,9 @@ public: ReadGuard l(m_lock); auto ret = m_blocksGot; if (!_desperate) - { - ReadGuard l(x_subs); - for (auto i: m_subs) - ret += i->m_asked; - } + DEV_READ_GUARDED(x_subs) + for (auto i: m_subs) + ret += i->m_asked; return ret; } @@ -144,12 +146,15 @@ public: h256s remaining() const { h256s ret; - ReadGuard l(m_lock); - for (auto i: m_blocksGot.inverted()) - ret.push_back(m_chain[i]); + DEV_READ_GUARDED(m_lock) + for (auto i: m_blocksGot.inverted()) + ret.push_back(m_chain[i]); return ret; } + h256 firstBlock() const { return m_chain.empty() ? h256() : m_chain[0]; } + Overview overview() const; + size_t chainSize() const { ReadGuard l(m_lock); return m_chain.size(); } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chain.empty(); } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); }