diff --git a/CMakeLists.txt b/CMakeLists.txt index 56ef68e32..ac5febd62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,7 +190,7 @@ else () set(SOLIDITY OFF) endif() if (SERPENT) - set(SERPENT ON) + set(SERPENT ${DECENT_PLATFORM}) else () set(SERPENT OFF) endif() @@ -216,7 +216,7 @@ else () set(ETHASHCL OFF) endif() if (NCURSES) - set(NCURSES ON) + set(NCURSES ${DECENT_PLATFORM}) else () set(NCURSES OFF) endif () @@ -230,7 +230,7 @@ if (BUNDLE STREQUAL "minimal") set(TOOLS ON) set(TESTS OFF) elseif (BUNDLE STREQUAL "full") - set(SERPENT ON) + set(SERPENT ${DECENT_PLATFORM}) set(SOLIDITY ON) set(USENPM ON) set(GUI ON) @@ -239,7 +239,7 @@ elseif (BUNDLE STREQUAL "full") set(TESTS ON) set(FATDB ON) elseif (BUNDLE STREQUAL "tests") - set(SERPENT ON) + set(SERPENT ${DECENT_PLATFORM}) set(SOLIDITY ON) set(USENPM OFF) set(GUI OFF) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index b59c9ce2d..14f3f5b67 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -45,6 +45,13 @@ + + + + #0 + + + @@ -118,7 +125,7 @@ 0 0 1617 - 22 + 24 diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a15bc833d..33ced7e98 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -161,8 +161,11 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->peerCount); statusBar()->addPermanentWidget(ui->mineStatus); + statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); + ui->blockCount->setText(QString("PV%2 D%3 H%4 v%5").arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(c_ethashVersion).arg(dev::Version)); + connect(ui->ourAccounts->model(), SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), SLOT(ourAccountsRowsMoved())); QSettings s("ethereum", "alethzero"); @@ -301,16 +304,25 @@ unsigned Main::installWatch(dev::h256 _tf, WatchHandler const& _f) void Main::uninstallWatch(unsigned _w) { + cdebug << "!!! Main: uninstalling watch" << _w; ethereum()->uninstallWatch(_w); m_handlers.erase(_w); } void Main::installWatches() { + auto newBlockId = installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ + onNewBlock(); + }); + auto newPendingId = installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ + onNewPending(); + }); + + cdebug << "newBlock watch ID: " << newBlockId; + cdebug << "newPending watch ID: " << newPendingId; + installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installNameRegWatch(); }); installWatch(LogFilter().address(c_newConfig), [=](LocalisedLogEntries const&) { installCurrenciesWatch(); }); - installWatch(PendingChangedFilter, [=](LocalisedLogEntries const&){ onNewPending(); }); - installWatch(ChainChangedFilter, [=](LocalisedLogEntries const&){ onNewBlock(); }); } Address Main::getNameReg() const @@ -1089,9 +1101,9 @@ void Main::refreshAccounts() void Main::refreshBlockCount() { - cwatch << "refreshBlockCount()"; auto d = ethereum()->blockChain().details(); - ui->blockCount->setText(QString("%4 #%1 PV%2 D%3 H%5").arg(d.number).arg(eth::c_protocolVersion).arg(c_databaseVersion).arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(c_ethashVersion)); + BlockQueueStatus b = ethereum()->blockQueueStatus(); + ui->chainStatus->setText(QString("%3 ready %4 future %5 unknown %6 bad %1 #%2").arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.ready).arg(b.future).arg(b.unknown).arg(b.bad)); } void Main::on_turboMining_triggered() @@ -1270,6 +1282,7 @@ void Main::timerEvent(QTimerEvent*) refreshNetwork(); refreshWhispers(); refreshCache(); + refreshBlockCount(); poll(); } else diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 883914ea6..dc0f42bf7 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.4"; +char const* Version = "0.9.5"; } diff --git a/libethcore/Common.h b/libethcore/Common.h index 56f1b704a..ec826d2d1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -92,7 +92,8 @@ enum class ImportResult FutureTime, AlreadyInChain, AlreadyKnown, - Malformed + Malformed, + BadChain }; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 74aeb4fad..a4061a1a0 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -306,39 +306,49 @@ LastHashes BlockChain::lastHashes(unsigned _n) const return m_lastLastHashes; } -pair BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) +tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { _bq.tick(*this); vector blocks; _bq.drain(blocks, _max); - h256s ret; + h256s fresh; + h256s dead; + h256s badBlocks; for (auto const& block: blocks) { try { - for (auto h: import(block, _stateDB)) - ret.push_back(h); + auto r = import(block, _stateDB); + bool isOld = true; + for (auto const& h: r.first) + if (h == r.second) + isOld = false; + else if (isOld) + dead.push_back(h); + else + fresh.push_back(h); } catch (UnknownParent) { - cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged() << boost::current_exception_diagnostic_information(); - _bq.import(&block, *this); + cwarn << "ODD: Import queue contains block with unknown parent." << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(BlockInfo::headerHash(block)); } catch (Exception const& _e) { - cwarn << "Unexpected exception!" << diagnostic_information(_e); - _bq.import(&block, *this); + cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << diagnostic_information(_e); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(BlockInfo::headerHash(block)); } - catch (...) - {} } - bool yetMore = _bq.doneDrain(); - return make_pair(ret, yetMore); + return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } -h256s BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force) noexcept +pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force) noexcept { try { @@ -347,11 +357,11 @@ h256s BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, catch (...) { cwarn << "Unexpected exception! Could not import block!" << boost::current_exception_diagnostic_information(); - return h256s(); + return make_pair(h256s(), h256()); } } -h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) +pair BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -532,14 +542,14 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) ); // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; - h256s ret; + h256s route; + h256 common; // This might be the new best block... h256 last = currentHash(); if (td > details(last).totalDifficulty) { - h256 common; unsigned commonIndex; - tie(ret, common, commonIndex) = treeRoute(last, newHash); + tie(route, common, commonIndex) = treeRoute(last, newHash); { WriteGuard l(x_lastBlockHash); m_lastBlockHash = newHash; @@ -554,7 +564,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) clearBlockBlooms(number(common) + 1, number(last) + 1); // Go through ret backwards until hash != last.parent and update m_transactionAddresses, m_blockHashes - for (auto i = ret.rbegin(); i != ret.rend() && *i != common; ++i) + for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) { auto b = block(*i); BlockInfo bi(b); @@ -606,7 +616,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp())); } - clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(ret); + clog(BlockChainNote) << " Imported and best" << td << ". Has" << (details(bi.parentHash).children.size() - 1) << "siblings. Route:" << toString(route); noteCanonChanged(); StructuredLogger::chainNewHead( @@ -631,7 +641,7 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _force) cnote << "checkBest:" << checkBest; #endif - return ret; + return make_pair(route, common); } void BlockChain::clearBlockBlooms(unsigned _begin, unsigned _end) @@ -704,21 +714,21 @@ tuple BlockChain::treeRoute(h256 const& _from, h256 const tn--; // cdebug << "to:" << tn << _to.abridged(); } - while (from != to) + for (;; from = details(from).parent, to = details(to).parent) { - if (!from) - assert(from); - if (!to) - assert(to); - from = details(from).parent; - to = details(to).parent; if (_pre && (from != to || _common)) ret.push_back(from); if (_post && (from != to || (!_pre && _common))) back.push_back(to); fn--; tn--; - // cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); +// cdebug << "from:" << fn << _from.abridged() << "; to:" << tn << _to.abridged(); + if (from == to) + break; + if (!from) + assert(from); + if (!to) + assert(to); } ret.reserve(ret.size() + back.size()); unsigned i = ret.size() - (int)(_common && !ret.empty() && !back.empty()); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 83b1926e8..70432f19c 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -100,15 +100,15 @@ public: void process(); /// Sync the chain with any incoming blocks. All blocks should, if processed in order - std::pair sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); + std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - h256s attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force = false) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _force = false) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - h256s import(bytes const& _block, OverlayDB const& _stateDB, bool _force = false); + std::pair import(bytes const& _block, OverlayDB const& _stateDB, bool _force = false); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -178,6 +178,10 @@ public: bytes transaction(h256 const& _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); } bytes transaction(unsigned _i) const { return transaction(currentHash(), _i); } + /// Get all transactions from a block. + std::vector transactions(h256 const& _blockHash) const { bytes b = block(_blockHash); std::vector ret; for (auto const& i: RLP(b)[1]) ret.push_back(i.data().toBytes()); return ret; } + std::vector transactions() const { return transactions(currentHash()); } + /// Get a number for the given hash (or the most recent mined if none given). Thread-safe. unsigned number(h256 const& _hash) const { return details(_hash).number; } unsigned number() const { return number(currentHash()); } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 69e387923..25f6ad438 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -38,7 +38,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) UpgradableGuard l(m_lock); - if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h)) + if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h)) { // Already know about this one. cblockq << "Already known."; @@ -48,20 +48,17 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; -#if ETH_CATCH try -#endif { + // TODO: quick verify bi.populate(_block); bi.verifyInternals(_block); } -#if ETH_CATCH catch (Exception const& _e) { cwarn << "Ignoring malformed block: " << diagnostic_information(_e); return ImportResult::Malformed; } -#endif // Check block doesn't already exist first! if (_bc.details(h)) @@ -82,7 +79,13 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) else { // We now know it. - if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + if (m_knownBad.count(bi.parentHash)) + { + m_knownBad.insert(bi.hash()); + // bad parent; this is bad too, note it as such + return ImportResult::BadChain; + } + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. cblockq << "OK - queued as unknown parent:" << bi.parentHash.abridged(); @@ -104,6 +107,35 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) } } +namespace dev { +template std::set& operator+=(std::set& _a, U const& _b) +{ + for (auto const& i: _b) + _a.insert(i); + return _a; +} } + +bool BlockQueue::doneDrain(h256s const& _bad) +{ + WriteGuard l(m_lock); + m_drainingSet.clear(); + if (_bad.size()) + { + vector old; + swap(m_ready, old); + for (auto& b: old) + { + BlockInfo bi(b); + if (m_knownBad.count(bi.parentHash)) + m_knownBad.insert(bi.hash()); + else + m_ready.push_back(std::move(b)); + } + } + m_knownBad += _bad; + return !m_readySet.empty(); +} + void BlockQueue::tick(BlockChain const& _bc) { unsigned t = time(0); diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index f34a53812..ce0582db2 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -38,6 +38,14 @@ class BlockChain; struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; }; #define cblockq dev::LogOutputStream() +struct BlockQueueStatus +{ + size_t ready; + size_t future; + size_t unknown; + size_t bad; +}; + /** * @brief A queue of blocks. Sits between network or other I/O and the BlockChain. * Sorts them ready for blockchain insertion (with the BlockChain::sync() method). @@ -58,7 +66,7 @@ public: /// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them. /// @returns true iff there are additional blocks ready to be processed. - bool doneDrain() { WriteGuard l(m_lock); m_drainingSet.clear(); return !m_readySet.empty(); } + bool doneDrain(h256s const& _knownBad = h256s()); /// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain). void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } @@ -72,6 +80,9 @@ public: /// Return first block with an unknown parent. h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); } + /// Get some infomration on the current status. + BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + private: void noteReadyWithoutWriteGuard(h256 _b); void notePresentWithoutWriteGuard(bytesConstRef _block); @@ -83,6 +94,7 @@ private: std::set m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain. std::multimap> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. std::multimap m_future; ///< Set of blocks that are not yet valid. + std::set m_knownBad; ///< Set of blocks that we know will never be valid. }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 71a9a4dbe..c8d0482c2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -453,6 +453,7 @@ void Client::doWork() // TODO: enable a short-circuit option since we mined it. will need to get the end state from the miner. auto lm = dynamic_cast(&m); h256s hs; + h256 c; if (false && lm && !m_verifyOwnBlocks) { // TODO: implement @@ -463,12 +464,13 @@ void Client::doWork() { cwork << "CHAIN <== postSTATE"; WriteGuard l(x_stateDB); - hs = m_bc.attemptImport(m.blockData(), m_stateDB); + tie(hs, c) = m_bc.attemptImport(m.blockData(), m_stateDB); } if (hs.size()) { for (auto const& h: hs) - appendFromNewBlock(h, changeds); + if (h != c) + appendFromNewBlock(h, changeds); changeds.insert(ChainChangedFilter); } for (auto& m: m_localMiners) @@ -498,18 +500,28 @@ void Client::doWork() cwork << "BQ ==> CHAIN ==> STATE"; OverlayDB db = m_stateDB; x_stateDB.unlock(); - h256s newBlocks; + h256s fresh; + h256s dead; bool sgw; - tie(newBlocks, sgw) = m_bc.sync(m_bq, db, 100); // TODO: remove transactions from m_tq nicely rather than relying on out of date nonce later on. + tie(fresh, dead, sgw) = m_bc.sync(m_bq, db, 100); + + // TODO: remove transactions from m_tq nicely rather than relying on out of date nonce later on. + for (auto const& h: dead) + for (auto const& t: m_bc.transactions(h)) + m_tq.import(t); + for (auto const& h: fresh) + for (auto const& th: m_bc.transactionHashes(h)) + m_tq.drop(th); + stillGotWork = stillGotWork | sgw; - if (newBlocks.size()) + if (!fresh.empty()) { - for (auto i: newBlocks) + for (auto i: fresh) appendFromNewBlock(i, changeds); changeds.insert(ChainChangedFilter); } x_stateDB.lock(); - if (newBlocks.size()) + if (fresh.size()) m_stateDB = db; cwork << "preSTATE <== CHAIN"; diff --git a/libethereum/Client.h b/libethereum/Client.h index f07e4c590..1891f34ca 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -168,6 +168,8 @@ public: dev::eth::State postState() const { ReadGuard l(x_stateDB); return m_postMine; } /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } + /// Get some information on the block queue. + BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } // Mining stuff: diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 557b08818..10e4ca84b 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -108,6 +108,7 @@ public: virtual LocalisedLogEntries peekWatch(unsigned _watchId) const override; virtual LocalisedLogEntries checkWatch(unsigned _watchId) override; + // TODO: switch all the _blockHash arguments to also accept _blockNumber virtual h256 hashFromNumber(unsigned _number) const override; virtual eth::BlockInfo blockInfo(h256 _hash) const override; virtual eth::BlockDetails blockDetails(h256 _hash) const override; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 5bc42540f..de85d94bb 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -162,6 +162,11 @@ void EthereumHost::doWork() maintainTransactions(); maintainBlocks(h); } + + for (auto p: peerSessions()) + if (shared_ptr const& ep = p.first->cap()) + ep->tick(); + // return netChange; // TODO: Figure out what to do with netChange. (void)netChange; @@ -201,16 +206,22 @@ void EthereumHost::maintainBlocks(h256 _currentHash) { clog(NetMessageSummary) << "Sending a new block (current is" << _currentHash << ", was" << m_latestBlockSent << ")"; - for (auto j: peerSessions()) + std::vector> dispersal; + for (auto const& j: peerSessions()) + if (!j.first->cap()->m_knownBlocks.count(_currentHash)) + dispersal.push_back(j.first->cap()); + + for (unsigned i = (dispersal.size() + 3) / 4; i--;) { - auto p = j.first->cap().get(); + unsigned n = rand() % dispersal.size(); + auto p = std::move(dispersal[n]); + dispersal.erase(dispersal.begin() + n); RLPStream ts; p->prep(ts, NewBlockPacket, 2).appendRaw(m_chain.block(), 1).append(m_chain.details().totalDifficulty); Guard l(p->x_knownBlocks); - if (!p->m_knownBlocks.count(_currentHash)) - p->sealAndSend(ts); + p->sealAndSend(ts); p->m_knownBlocks.clear(); } m_latestBlockSent = _currentHash; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index ca0195efe..3bd7ecab3 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -220,6 +220,8 @@ void EthereumPeer::setAsking(Asking _a, bool _isSyncing) m_syncingNeededBlocks.clear(); } + m_lastAsk = chrono::system_clock::now(); + session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : "")); } @@ -235,6 +237,13 @@ void EthereumPeer::setNeedsSyncing(h256 _latestHash, u256 _td) session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : "")); } +void EthereumPeer::tick() +{ + if (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing) + // timeout + session()->disconnect(PingTimeout); +} + bool EthereumPeer::isSyncing() const { return host()->m_syncer == this; @@ -451,6 +460,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) break; case ImportResult::Malformed: + case ImportResult::BadChain: disable("Malformed block received."); return true; @@ -505,8 +515,9 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) break; case ImportResult::Malformed: + case ImportResult::BadChain: disable("Malformed block received."); - break; + return true; case ImportResult::AlreadyInChain: case ImportResult::AlreadyKnown: diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index c95df6945..da144134b 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -105,6 +105,9 @@ private: /// Check whether the session should bother grabbing the peer's blocks. bool shouldGrabBlocks() const; + /// Runs period checks to check up on the peer. + void tick(); + /// Peer's protocol version. unsigned m_protocolVersion; /// Peer's network id. @@ -112,6 +115,8 @@ private: /// What, if anything, we last asked the other peer for. Asking m_asking = Asking::Nothing; + /// When we asked for it. Allows a time out. + std::chrono::system_clock::time_point m_lastAsk; /// Whether this peer is in the process of syncing or not. Only one peer can be syncing at once. bool m_isSyncing = false; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index da0108b3e..79fd75d77 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -385,7 +385,7 @@ string WebThreeStubServerBase::eth_getBlockTransactionCountByNumber(string const { try { - return toJS(client()->transactionCount(client()->hashFromNumber(toBlockNumber(_blockNumber)))); + return toJS(_blockNumber == "pending" ? client()->pending().size() : client()->transactionCount(client()->hashFromNumber(toBlockNumber(_blockNumber)))); } catch (...) {