Browse Source

More sophisticated (and correct) BlockHashes handling.

cl-refactor
Gav Wood 10 years ago
parent
commit
e179781728
  1. 15
      libdevcore/RLP.cpp
  2. 7
      libdevcore/RLP.h
  3. 3
      libethcore/Common.h
  4. 2
      libethereum/BlockChain.cpp
  5. 15
      libethereum/BlockQueue.cpp
  6. 11
      libethereum/BlockQueue.h
  7. 11
      libethereum/EthereumPeer.cpp

15
libdevcore/RLP.cpp

@ -111,10 +111,24 @@ unsigned RLP::actualSize() const
return 0;
}
void RLP::requireGood() const
{
if (isNull())
BOOST_THROW_EXCEPTION(BadRLP());
byte n = m_data[0];
if (n != c_rlpDataImmLenStart + 1)
return;
if (m_data.size() < 2)
BOOST_THROW_EXCEPTION(BadRLP());
if (m_data[1] < c_rlpDataImmLenStart)
BOOST_THROW_EXCEPTION(BadRLP());
}
bool RLP::isInt() const
{
if (isNull())
return false;
requireGood();
byte n = m_data[0];
if (n < c_rlpDataImmLenStart)
return !!n;
@ -141,6 +155,7 @@ unsigned RLP::length() const
{
if (isNull())
return 0;
requireGood();
unsigned ret = 0;
byte n = m_data[0];
if (n < c_rlpDataImmLenStart)

7
libdevcore/RLP.h

@ -253,6 +253,7 @@ public:
/// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string.
template <class _T = unsigned> _T toInt(int _flags = Strict) const
{
requireGood();
if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast());
@ -273,6 +274,7 @@ public:
template <class _N> _N toHash(int _flags = Strict) const
{
requireGood();
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall)))
if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast());
@ -290,7 +292,7 @@ public:
RLPs toList() const;
/// @returns the data payload. Valid for all types.
bytesConstRef payload() const { return m_data.cropped(payloadOffset()); }
bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); }
/// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
@ -300,6 +302,9 @@ private:
/// Disable construction from rvalue
explicit RLP(bytes const&&) {}
/// Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one).
void requireGood() const;
/// Single-byte data payload.
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }

3
libethcore/Common.h

@ -90,8 +90,7 @@ enum class ImportResult
AlreadyInChain,
AlreadyKnown,
Malformed,
BadChain,
Unknown
BadChain
};
struct ImportRequirements

2
libethereum/BlockChain.cpp

@ -310,7 +310,7 @@ tuple<h256s, h256s, bool> BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
fresh += r.first;
dead += r.second;
}
catch (UnknownParent)
catch (dev::eth::UnknownParent)
{
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.

15
libethereum/BlockQueue.cpp

@ -169,6 +169,21 @@ template <class T> T advanced(T _t, unsigned _n)
return _t;
}
QueueStatus BlockQueue::blockStatus(h256 const& _h) const
{
ReadGuard l(m_lock);
return
m_readySet.count(_h) ?
QueueStatus::Ready :
m_drainingSet.count(_h) ?
QueueStatus::Importing :
m_unknownSet.count(_h) ?
QueueStatus::UnknownParent :
m_knownBad.count(_h) ?
QueueStatus::Bad :
QueueStatus::Unknown;
}
void BlockQueue::drain(std::vector<bytes>& o_out, unsigned _max)
{
WriteGuard l(m_lock);

11
libethereum/BlockQueue.h

@ -46,6 +46,15 @@ struct BlockQueueStatus
size_t bad;
};
enum class QueueStatus
{
Ready,
Importing,
UnknownParent,
Bad,
Unknown
};
/**
* @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).
@ -87,7 +96,7 @@ public:
BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
/// Get some infomration on the given block's status regarding us.
ImportResult blockStatus(h256 const& _h) const { ReadGuard l(m_lock); return m_readySet.count(_h) || m_drainingSet.count(_h) ? ImportResult::AlreadyKnown : m_unknownSet.count(_h) ? ImportResult::UnknownParent : m_knownBad.count(_h) ? ImportResult::BadChain : ImportResult::Unknown; }
QueueStatus blockStatus(h256 const& _h) const;
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }

11
libethereum/EthereumPeer.cpp

@ -389,12 +389,19 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r)
{
addRating(1);
auto h = _r[i].toHash<h256>();
if (host()->m_bq.blockStatus(h) != ImportResult::Unknown || host()->m_chain.isKnown(h))
auto status = host()->m_bq.blockStatus(h);
if (status == QueueStatus::Importing || status == QueueStatus::Ready || host()->m_chain.isKnown(h))
{
transition(Asking::Blocks);
return true;
}
else
else if (status == QueueStatus::Bad)
{
cwarn << "BAD hash chain discovered. Ignoring.";
transition(Asking::Nothing);
return true;
}
else if (status == QueueStatus::Unknown)
m_syncingNeededBlocks.push_back(h);
}
// run through - ask for more.

Loading…
Cancel
Save