From b7b17b996345782c13a726a710ba4a95466932c4 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 8 Sep 2014 19:30:55 +0200 Subject: [PATCH] Queue future blocks, don't discard. --- libdevcore/Common.cpp | 2 +- libethereum/BlockChain.cpp | 10 ++++++- libethereum/BlockQueue.cpp | 45 ++++++++++++++++++++++---------- libethereum/BlockQueue.h | 13 ++++++--- libethereum/CommonNet.h | 8 +++--- libethereum/TransactionQueue.cpp | 10 +++---- libethereum/TransactionQueue.h | 4 +-- 7 files changed, 61 insertions(+), 31 deletions(-) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 665a663f3..325ba274e 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -27,7 +27,7 @@ using namespace dev; namespace dev { -char const* Version = "0.6.8"; +char const* Version = "0.6.8b"; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index c23258f08..716add2ae 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -178,6 +178,8 @@ inline string toString(h256s const& _bs) h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { + _bq.tick(*this); + vector blocks; _bq.drain(blocks); @@ -197,7 +199,13 @@ h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged(); _bq.import(&block, *this); } - catch (...){} + catch (Exception const& _e) + { + cwarn << "Unexpected exception!" << _e.description(); + _bq.import(&block, *this); + } + catch (...) + {} } _bq.doneDrain(); return ret; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f8bc7d64c..24f979072 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -38,7 +38,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) UpgradableGuard l(m_lock); - if (m_readySet.count(h) || m_drainingSet.count(h) || m_futureSet.count(h)) + if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h)) { // Already know about this one. cnote << "Already known."; @@ -70,23 +70,20 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) return false; } - // Check it's not crazy - if (bi.timestamp > (u256)time(0) + 10) - { - cnote << "Invalid timestamp."; - return false; - } + UpgradeGuard ul(l); + // Check it's not in the future + if (bi.timestamp > (u256)time(0)) + m_future.insert(make_pair((unsigned)bi.timestamp, _block.toBytes())); + else { - UpgradeGuard ul(l); - // We now know it. if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(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. // cnote << "OK - queued for future."; - m_future.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); - m_futureSet.insert(h); + m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + m_unknownSet.insert(h); } else { @@ -102,21 +99,41 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) return true; } +void BlockQueue::tick(BlockChain const& _bc) +{ + unsigned t = time(0); + for (auto i = m_future.begin(); i != m_future.end() && i->first < time(0); ++i) + import(&(i->second), _bc); + + WriteGuard l(m_lock); + m_future.erase(m_future.begin(), m_future.upper_bound(t)); +} + +void BlockQueue::drain(std::vector& o_out) +{ + WriteGuard l(m_lock); + if (m_drainingSet.empty()) + { + swap(o_out, m_ready); + swap(m_drainingSet, m_readySet); + } +} + void BlockQueue::noteReadyWithoutWriteGuard(h256 _good) { list goodQueue(1, _good); while (goodQueue.size()) { - auto r = m_future.equal_range(goodQueue.front()); + auto r = m_unknown.equal_range(goodQueue.front()); goodQueue.pop_front(); for (auto it = r.first; it != r.second; ++it) { m_ready.push_back(it->second.second); auto newReady = it->second.first; - m_futureSet.erase(newReady); + m_unknownSet.erase(newReady); m_readySet.insert(newReady); goodQueue.push_back(newReady); } - m_future.erase(r.first, r.second); + m_unknown.erase(r.first, r.second); } } diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index c68e1f1e4..2aaae3280 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -44,9 +44,12 @@ public: /// Import a block into the queue. bool import(bytesConstRef _tx, BlockChain const& _bc); + /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. + void tick(BlockChain const& _bc); + /// Grabs the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. - void drain(std::vector& o_out) { WriteGuard l(m_lock); if (m_drainingSet.empty()) { swap(o_out, m_ready); swap(m_drainingSet, m_readySet); } } + void drain(std::vector& o_out); /// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them. void doneDrain() { WriteGuard l(m_lock); m_drainingSet.clear(); } @@ -55,17 +58,19 @@ public: void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } /// Get information on the items queued. - std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_future.size()); } + std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); } private: void noteReadyWithoutWriteGuard(h256 _b); + void notePresentWithoutWriteGuard(bytesConstRef _block); mutable boost::shared_mutex m_lock; ///< General lock. std::set m_readySet; ///< All blocks ready for chain-import. std::set m_drainingSet; ///< All blocks being imported. std::vector m_ready; ///< List of blocks, in correct order, ready for chain-import. - std::set m_futureSet; ///< Set of all blocks whose parents are not ready/in-chain. - std::multimap> m_future; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears. + 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. }; } diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index 13f68a977..3bb45b55d 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -33,10 +33,10 @@ namespace dev namespace eth { -static const unsigned c_maxHashes = 32; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 32; ///< Maximum number of hashes GetBlockHashes will ever ask for. -static const unsigned c_maxBlocks = 16; ///< Maximum number of blocks Blocks will ever send. -static const unsigned c_maxBlocksAsk = 16; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxHashes = 256; ///< Maximum number of hashes BlockHashes will ever send. +static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. +static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). class OverlayDB; class BlockChain; diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 5275732cb..f15cefc26 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -69,17 +69,17 @@ void TransactionQueue::setFuture(std::pair const& _t) if (m_current.count(_t.first)) { m_current.erase(_t.first); - m_future.insert(make_pair(Transaction(_t.second).sender(), _t)); + m_unknown.insert(make_pair(Transaction(_t.second).sender(), _t)); } } void TransactionQueue::noteGood(std::pair const& _t) { WriteGuard l(m_lock); - auto r = m_future.equal_range(Transaction(_t.second).sender()); + auto r = m_unknown.equal_range(Transaction(_t.second).sender()); for (auto it = r.first; it != r.second; ++it) m_current.insert(it->second); - m_future.erase(r.first, r.second); + m_unknown.erase(r.first, r.second); } void TransactionQueue::drop(h256 _txHash) @@ -96,10 +96,10 @@ void TransactionQueue::drop(h256 _txHash) m_current.erase(_txHash); else { - for (auto i = m_future.begin(); i != m_future.end(); ++i) + for (auto i = m_unknown.begin(); i != m_unknown.end(); ++i) if (i->second.first == _txHash) { - m_future.erase(i); + m_unknown.erase(i); break; } } diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 690dc658a..154eed9d2 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -47,7 +47,7 @@ public: void drop(h256 _txHash); std::map transactions() const { ReadGuard l(m_lock); return m_current; } - std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_future.size()); } + std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); } void setFuture(std::pair const& _t); void noteGood(std::pair const& _t); @@ -56,7 +56,7 @@ private: mutable boost::shared_mutex m_lock; ///< General lock. std::set m_known; ///< Hashes of transactions in both sets. std::map m_current; ///< Map of SHA3(tx) to tx. - std::multimap> m_future; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. + std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. }; }