diff --git a/alethzero/DownloadView.cpp b/alethzero/DownloadView.cpp index 5112f961c..046b8973a 100644 --- a/alethzero/DownloadView.cpp +++ b/alethzero/DownloadView.cpp @@ -52,7 +52,7 @@ void SyncView::paintEvent(QPaintEvent*) unsigned syncVerified = syncImporting + bqs.verified; unsigned syncVerifying = syncVerified + bqs.verifying; unsigned syncUnverified = syncVerifying + bqs.unverified; - unsigned syncUnknown = syncUnverified + bqs.unknown; + unsigned syncCount = syncUnverified + bqs.unknown - syncFrom; // best effort guess. assumes there's no forks. unsigned downloadFrom = m_client->numberFromHash(m_client->isKnown(man->firstBlock()) ? man->firstBlock() : PendingBlockHash); @@ -67,17 +67,19 @@ void SyncView::paintEvent(QPaintEvent*) unsigned hashDone = hashFrom + (sync.state == SyncState::Hashes ? sync.hashesReceived : hashCount); m_lastFrom = min(syncFrom, m_lastFrom); + m_lastTo = max(max(syncFrom + syncCount, hashFrom + hashCount), m_lastTo); 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; + unsigned count = max(max(hashFrom + hashCount, downloadFrom + downloadCount), max(syncFrom + syncCount, m_lastTo)) - from; + m_lastFrom = (m_lastFrom * 99 + syncFrom * 1) / 100; + m_lastTo = (m_lastTo * 99 + max(syncFrom + syncCount, hashFrom + hashCount) * 1) / 100; if (!count) { - m_lastFrom = (unsigned)-1; + m_lastFrom = m_lastTo = (unsigned)-1; return; } - cnote << "Range " << from << "-" << (from + count); + cnote << "Range " << from << "-" << (from + count) << "(" << hashFrom << "+" << hashCount << "," << downloadFrom << "+" << downloadCount << "," << syncFrom << "+" << syncCount << ")"; auto r = [&](unsigned u) { return toString((u - from) * 100 / count) + "%"; }; @@ -85,27 +87,48 @@ void SyncView::paintEvent(QPaintEvent*) 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); + cnote << "Importing:" << r(syncFrom) << r(syncImported) << r(syncImporting) << r(syncVerified) << r(syncVerifying) << r(syncUnverified); } - if (!man || man->chainEmpty() || !man->subCount()) - return; - - float s = min(rect().width(), rect().height()); + float squareSize = min(rect().width(), rect().height()); QPen pen; pen.setCapStyle(Qt::FlatCap); - pen.setWidthF(s / 10); - p.setPen(pen); + pen.setWidthF(squareSize / 20); auto middle = [&](float x) { - return QRectF(s / 2 - s / 2 * x, 0 + s / 2 - s / 2 * x, s * x, s * x); + return QRectF(squareSize / 2 - squareSize / 2 * x, 0 + squareSize / 2 - squareSize / 2 * x, squareSize * x, squareSize * x); + }; + + auto arcLen = [&](unsigned x) { + return x * -5760.f / count; + }; + auto arcPos = [&](unsigned x) { + return int(90 * 16.f + arcLen(x - from)) % 5760; }; - auto toArc = [&](unsigned x) { - return (x - from) * -5760.f / count; + p.setPen(Qt::NoPen); + p.setBrush(QColor::fromHsv(0, 0, 210)); + pen.setWidthF(0.f); + p.drawPie(middle(0.4f), arcPos(from), arcLen(hashDone - from)); + + auto progress = [&](unsigned h, unsigned s, unsigned v, float size, float thickness, unsigned nfrom, unsigned ncount) { + p.setBrush(Qt::NoBrush); + pen.setColor(QColor::fromHsv(h, s, v)); + pen.setWidthF(squareSize * thickness); + p.setPen(pen); + p.drawArc(middle(size), arcPos(nfrom), arcLen(ncount)); }; - const float arcFrom = 90 * 16.f; - p.drawArc(middle(0.5f), arcFrom, toArc(downloadDone)); - p.drawPie(middle(0.2f), arcFrom, toArc(hashDone)); + + progress(0, 50, 170, 0.4f, 0.12f, downloadFlank, downloadPoint - downloadFlank); + progress(0, 0, 150, 0.4f, 0.10f, from, downloadDone - from); + + progress(0, 0, 230, 0.7f, 0.090f, from, syncUnverified - from); + progress(60, 25, 210, 0.7f, 0.08f, from, syncVerifying - from); + progress(120, 25, 190, 0.7f, 0.07f, from, syncVerified - from); + + progress(0, 0, 220, 0.9f, 0.02f, from, count); + progress(0, 0, 100, 0.9f, 0.04f, from, syncFrom - from); + progress(0, 50, 100, 0.9f, 0.08f, syncFrom, syncImporting - syncFrom); + return; double ratio = (double)rect().width() / rect().height(); diff --git a/alethzero/DownloadView.h b/alethzero/DownloadView.h index 9ee2428b2..71fc41f3f 100644 --- a/alethzero/DownloadView.h +++ b/alethzero/DownloadView.h @@ -51,4 +51,5 @@ private: dev::eth::Client const* m_client = nullptr; unsigned m_lastFrom = (unsigned)-1; + unsigned m_lastTo = (unsigned)-1; }; diff --git a/alethzero/Main.ui b/alethzero/Main.ui index 37ff7f66c..97853e174 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -199,6 +199,7 @@ + @@ -1804,6 +1805,11 @@ font-size: 14pt &Sentinel... + + + &Rewind Chain... + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ba4bec863..60c07fd8d 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1044,6 +1044,17 @@ void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter void Main::on_vmJIT_triggered() { VMFactory::setKind(VMKind::JIT); } void Main::on_vmSmart_triggered() { VMFactory::setKind(VMKind::Smart); } +void Main::on_rewindChain_triggered() +{ + bool ok; + int n = QInputDialog::getInt(this, "Rewind Chain", "Enter the number of the new chain head.", ethereum()->number() * 9 / 10, 1, ethereum()->number(), 1, &ok); + if (ok) + { + ethereum()->rewind(n); + refreshAll(); + } +} + void Main::on_urlEdit_returnPressed() { QString s = ui->urlEdit->text(); diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index b1939534b..0e944b042 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -187,6 +187,7 @@ private slots: void on_vmInterpreter_triggered(); void on_vmJIT_triggered(); void on_vmSmart_triggered(); + void on_rewindChain_triggered(); // Debugger void on_debugCurrent_triggered(); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index bf4eaf4d0..719ec016e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -799,6 +799,25 @@ void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) } } +void BlockChain::rewind(unsigned _newHead) +{ + DEV_WRITE_GUARDED(x_lastBlockHash) + { + if (_newHead >= m_lastBlockNumber) + return; + m_lastBlockHash = numberHash(_newHead); + m_lastBlockNumber = _newHead; + auto o = m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&m_lastBlockHash, 32)); + if (!o.ok()) + { + cwarn << "Error writing to extras database: " << o.ToString(); + cout << "Put" << toHex(bytesConstRef(ldb::Slice("best"))) << "=>" << toHex(bytesConstRef(ldb::Slice((char const*)&m_lastBlockHash, 32))); + cwarn << "Fail writing to extras database. Bombing out."; + exit(-1); + } + } +} + tuple BlockChain::treeRoute(h256 const& _from, h256 const& _to, bool _common, bool _pre, bool _post) const { // cdebug << "treeRoute" << _from << "..." << _to; @@ -1070,7 +1089,8 @@ bool BlockChain::isKnown(h256 const& _hash) const if (d.empty()) return false; } - return true; +// return true; + return details(_hash).number <= m_lastBlockNumber; // to allow rewind functionality. } bytes BlockChain::block(h256 const& _hash) const diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 4cffca2df..1d88430b0 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -215,6 +215,9 @@ public: /// Will call _progress with the progress in this operation first param done, second total. void rebuild(std::string const& _path, ProgressCallback const& _progress = std::function(), bool _prepPoW = false); + /// Alter the head of the chain to some prior block along it. + void rewind(unsigned _newHead); + /** @returns a tuple of: * - an vector of hashes of all blocks between @a _from and @a _to, all blocks are ordered first by a number of * blocks that are parent-to-child, then two sibling blocks, then a number of blocks that are child-to-parent; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 5e0a523d8..f95a3880e 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -215,8 +215,10 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::Malformed; } + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + // Check block doesn't already exist first! - if (_bc.details(h)) + if (_bc.isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; diff --git a/libethereum/Client.h b/libethereum/Client.h index 829ec77c1..fac54b010 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -217,6 +217,8 @@ public: std::string const& sentinel() const { return m_sentinel; } /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } + /// Rewind to a prior head. + void rewind(unsigned _n) { m_bc.rewind(_n); } protected: /// InterfaceStub methods diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f50545d08..10d637509 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1212,6 +1212,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per uncommitToMine(); // OK - transaction looks valid - execute. + u256 startGasUsed = gasUsed(); #if ETH_PARANOIA ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); @@ -1261,7 +1262,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per // Add to the user-originated transactions that we've executed. m_transactions.push_back(e.t()); - m_receipts.push_back(TransactionReceipt(rootHash(), e.gasUsed(), e.logs())); + m_receipts.push_back(TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs())); m_transactionSet.insert(e.t().sha3()); }