Browse Source

Queue future blocks, don't discard.

cl-refactor
Gav Wood 10 years ago
parent
commit
b7b17b9963
  1. 2
      libdevcore/Common.cpp
  2. 10
      libethereum/BlockChain.cpp
  3. 45
      libethereum/BlockQueue.cpp
  4. 13
      libethereum/BlockQueue.h
  5. 8
      libethereum/CommonNet.h
  6. 10
      libethereum/TransactionQueue.cpp
  7. 4
      libethereum/TransactionQueue.h

2
libdevcore/Common.cpp

@ -27,7 +27,7 @@ using namespace dev;
namespace dev namespace dev
{ {
char const* Version = "0.6.8"; char const* Version = "0.6.8b";
} }

10
libethereum/BlockChain.cpp

@ -178,6 +178,8 @@ inline string toString(h256s const& _bs)
h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) h256s BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{ {
_bq.tick(*this);
vector<bytes> blocks; vector<bytes> blocks;
_bq.drain(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(); cwarn << "Unknown parent of block!!!" << BlockInfo::headerHash(block).abridged();
_bq.import(&block, *this); _bq.import(&block, *this);
} }
catch (...){} catch (Exception const& _e)
{
cwarn << "Unexpected exception!" << _e.description();
_bq.import(&block, *this);
}
catch (...)
{}
} }
_bq.doneDrain(); _bq.doneDrain();
return ret; return ret;

45
libethereum/BlockQueue.cpp

@ -38,7 +38,7 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
UpgradableGuard l(m_lock); 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. // Already know about this one.
cnote << "Already known."; cnote << "Already known.";
@ -70,23 +70,20 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
return false; return false;
} }
// Check it's not crazy UpgradeGuard ul(l);
if (bi.timestamp > (u256)time(0) + 10)
{
cnote << "Invalid timestamp.";
return false;
}
// 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. // We now know it.
if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.details(bi.parentHash)) 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. // 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."; // cnote << "OK - queued for future.";
m_future.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes())));
m_futureSet.insert(h); m_unknownSet.insert(h);
} }
else else
{ {
@ -102,21 +99,41 @@ bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc)
return true; 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<bytes>& 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) void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
{ {
list<h256> goodQueue(1, _good); list<h256> goodQueue(1, _good);
while (goodQueue.size()) while (goodQueue.size())
{ {
auto r = m_future.equal_range(goodQueue.front()); auto r = m_unknown.equal_range(goodQueue.front());
goodQueue.pop_front(); goodQueue.pop_front();
for (auto it = r.first; it != r.second; ++it) for (auto it = r.first; it != r.second; ++it)
{ {
m_ready.push_back(it->second.second); m_ready.push_back(it->second.second);
auto newReady = it->second.first; auto newReady = it->second.first;
m_futureSet.erase(newReady); m_unknownSet.erase(newReady);
m_readySet.insert(newReady); m_readySet.insert(newReady);
goodQueue.push_back(newReady); goodQueue.push_back(newReady);
} }
m_future.erase(r.first, r.second); m_unknown.erase(r.first, r.second);
} }
} }

13
libethereum/BlockQueue.h

@ -44,9 +44,12 @@ public:
/// Import a block into the queue. /// Import a block into the queue.
bool import(bytesConstRef _tx, BlockChain const& _bc); 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. /// 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. /// Don't forget to call doneDrain() once you're done importing.
void drain(std::vector<bytes>& o_out) { WriteGuard l(m_lock); if (m_drainingSet.empty()) { swap(o_out, m_ready); swap(m_drainingSet, m_readySet); } } void drain(std::vector<bytes>& 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. /// 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(); } void doneDrain() { WriteGuard l(m_lock); m_drainingSet.clear(); }
@ -55,17 +58,19 @@ public:
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); } void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); }
/// Get information on the items queued. /// Get information on the items queued.
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_future.size()); } std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
private: private:
void noteReadyWithoutWriteGuard(h256 _b); void noteReadyWithoutWriteGuard(h256 _b);
void notePresentWithoutWriteGuard(bytesConstRef _block);
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_readySet; ///< All blocks ready for chain-import. std::set<h256> m_readySet; ///< All blocks ready for chain-import.
std::set<h256> m_drainingSet; ///< All blocks being imported. std::set<h256> m_drainingSet; ///< All blocks being imported.
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import. std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import.
std::set<h256> m_futureSet; ///< Set of all blocks whose parents are not ready/in-chain. std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
std::multimap<h256, std::pair<h256, bytes>> 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::multimap<h256, std::pair<h256, bytes>> 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<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
}; };
} }

8
libethereum/CommonNet.h

@ -33,10 +33,10 @@ namespace dev
namespace eth namespace eth
{ {
static const unsigned c_maxHashes = 32; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashes = 256; ///< 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_maxHashesAsk = 256; ///< 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_maxBlocks = 128; ///< 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_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
class OverlayDB; class OverlayDB;
class BlockChain; class BlockChain;

10
libethereum/TransactionQueue.cpp

@ -69,17 +69,17 @@ void TransactionQueue::setFuture(std::pair<h256, bytes> const& _t)
if (m_current.count(_t.first)) if (m_current.count(_t.first))
{ {
m_current.erase(_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<h256, bytes> const& _t) void TransactionQueue::noteGood(std::pair<h256, bytes> const& _t)
{ {
WriteGuard l(m_lock); 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) for (auto it = r.first; it != r.second; ++it)
m_current.insert(it->second); m_current.insert(it->second);
m_future.erase(r.first, r.second); m_unknown.erase(r.first, r.second);
} }
void TransactionQueue::drop(h256 _txHash) void TransactionQueue::drop(h256 _txHash)
@ -96,10 +96,10 @@ void TransactionQueue::drop(h256 _txHash)
m_current.erase(_txHash); m_current.erase(_txHash);
else 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) if (i->second.first == _txHash)
{ {
m_future.erase(i); m_unknown.erase(i);
break; break;
} }
} }

4
libethereum/TransactionQueue.h

@ -47,7 +47,7 @@ public:
void drop(h256 _txHash); void drop(h256 _txHash);
std::map<h256, bytes> transactions() const { ReadGuard l(m_lock); return m_current; } std::map<h256, bytes> transactions() const { ReadGuard l(m_lock); return m_current; }
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_future.size()); } std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_current.size(), m_unknown.size()); }
void setFuture(std::pair<h256, bytes> const& _t); void setFuture(std::pair<h256, bytes> const& _t);
void noteGood(std::pair<h256, bytes> const& _t); void noteGood(std::pair<h256, bytes> const& _t);
@ -56,7 +56,7 @@ private:
mutable boost::shared_mutex m_lock; ///< General lock. mutable boost::shared_mutex m_lock; ///< General lock.
std::set<h256> m_known; ///< Hashes of transactions in both sets. std::set<h256> m_known; ///< Hashes of transactions in both sets.
std::map<h256, bytes> m_current; ///< Map of SHA3(tx) to tx. std::map<h256, bytes> m_current; ///< Map of SHA3(tx) to tx.
std::multimap<Address, std::pair<h256, bytes>> 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<Address, std::pair<h256, bytes>> 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.
}; };
} }

Loading…
Cancel
Save