Ethereum  PoC-8
The C++ Implementation of Ethereum
BlockQueue.h
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #pragma once
23 
24 #include <condition_variable>
25 #include <thread>
26 #include <deque>
27 #include <boost/thread.hpp>
28 #include <libdevcore/Common.h>
29 #include <libdevcore/Log.h>
30 #include <libethcore/Common.h>
31 #include <libdevcore/Guards.h>
32 #include <libethcore/BlockHeader.h>
33 #include "VerifiedBlock.h"
34 
35 namespace dev
36 {
37 
38 namespace eth
39 {
40 
41 class BlockChain;
42 
44 {
45  size_t importing;
46  size_t verified;
47  size_t verifying;
48  size_t unverified;
49  size_t future;
50  size_t unknown;
51  size_t bad;
52 };
53 
54 enum class QueueStatus
55 {
56  Ready,
57  Importing,
59  Bad,
60  Unknown
61 };
62 
63 std::ostream& operator<< (std::ostream& os, QueueStatus const& obj);
64 
65 template<class T>
67 {
68 public:
69  std::size_t count() const { return m_queue.size(); }
70 
71  std::size_t size() const { return m_size; }
72 
73  bool isEmpty() const { return m_queue.empty(); }
74 
75  h256 nextHash() const { return m_queue.front().verified.info.sha3Uncles(); }
76 
77  T const& next() const { return m_queue.front(); }
78 
79  void clear()
80  {
81  m_queue.clear();
82  m_size = 0;
83  }
84 
85  void enqueue(T&& _t)
86  {
87  m_queue.emplace_back(std::move(_t));
88  m_size += m_queue.back().blockData.size();
89  }
90 
91  T dequeue()
92  {
93  T t;
94  std::swap(t, m_queue.front());
95  m_queue.pop_front();
96  m_size -= t.blockData.size();
97 
98  return t;
99  }
100 
101  std::vector<T> dequeueMultiple(std::size_t _n)
102  {
103  return removeRange(m_queue.begin(), m_queue.begin() + _n);
104  }
105 
106  bool remove(h256 const& _hash)
107  {
108  std::vector<T> removed = removeIf(sha3UnclesEquals(_hash));
109  return !removed.empty();
110  }
111 
112  template<class Pred>
113  std::vector<T> removeIf(Pred _pred)
114  {
115  auto const removedBegin = std::remove_if(m_queue.begin(), m_queue.end(), _pred);
116 
117  return removeRange(removedBegin, m_queue.end());
118  }
119 
120  bool replace(h256 const& _hash, T&& _t)
121  {
122  auto const it = std::find_if(m_queue.begin(), m_queue.end(), sha3UnclesEquals(_hash));
123 
124  if (it == m_queue.end())
125  return false;
126 
127  m_size -= it->blockData.size();
128  m_size += _t.blockData.size();
129  *it = std::move(_t);
130 
131  return true;
132  }
133 
134 private:
135  static std::function<bool(T const&)> sha3UnclesEquals(h256 const& _hash)
136  {
137  return [&_hash](T const& _t) { return _t.verified.info.sha3Uncles() == _hash; };
138  }
139 
140  std::vector<T> removeRange(typename std::deque<T>::iterator _begin, typename std::deque<T>::iterator _end)
141  {
142  std::vector<T> ret(std::make_move_iterator(_begin), std::make_move_iterator(_end));
143 
144  for (auto it = ret.begin(); it != ret.end(); ++it)
145  m_size -= it->blockData.size();
146 
147  m_queue.erase(_begin, _end);
148  return ret;
149  }
150 
151  std::deque<T> m_queue;
152  std::atomic<size_t> m_size = {0};
153 };
154 
155 template<class KeyType>
157 {
158 public:
159  std::size_t count() const { return m_map.size(); }
160 
161  std::size_t size() const { return m_size; }
162 
163  bool isEmpty() const { return m_map.empty(); }
164 
165  KeyType firstKey() const { return m_map.begin()->first; }
166 
167  void clear()
168  {
169  m_map.clear();
170  m_size = 0;
171  }
172 
173  void insert(KeyType const& _key, h256 const& _hash, bytes&& _blockData)
174  {
175  auto hashAndBlock = std::make_pair(_hash, std::move(_blockData));
176  auto keyAndValue = std::make_pair(_key, std::move(hashAndBlock));
177  m_map.insert(std::move(keyAndValue));
178  m_size += _blockData.size();
179  }
180 
181  // returns removed (hash, block data) pairs
182  std::vector<std::pair<h256, bytes>> removeByKeyEqual(KeyType const& _key)
183  {
184  auto const equalRange = m_map.equal_range(_key);
185  return removeRange(equalRange.first, equalRange.second);
186  }
187 
188  // returns removed (hash, block data) pairs
189  std::vector<std::pair<h256, bytes>> removeByKeyNotGreater(KeyType const& _key)
190  {
191  return removeRange(m_map.begin(), m_map.upper_bound(_key));
192  }
193 
194 private:
195  // map of key to (hash, block data) pairs
196  using BlockMultimap = std::multimap<KeyType, std::pair<h256, bytes>>;
197 
198  std::vector<std::pair<h256, bytes>> removeRange(typename BlockMultimap::iterator _begin, typename BlockMultimap::iterator _end)
199  {
200  std::vector<std::pair<h256, bytes>> removed;
201  std::size_t removedSize = 0;
202  for (auto it = _begin; it != _end; ++it)
203  {
204  removed.push_back(std::move(it->second));
205  removedSize += removed.back().second.size();
206  }
207 
208  m_size -= removedSize;
209  m_map.erase(_begin, _end);
210 
211  return removed;
212  }
213 
214  BlockMultimap m_map;
215  std::atomic<size_t> m_size = {0};
216 };
217 
224 {
225 public:
226  BlockQueue();
227  ~BlockQueue();
228 
229  void setChain(BlockChain const& _bc) { m_bc = &_bc; }
230 
232  ImportResult import(bytesConstRef _block, bool _isOurs = false);
233 
235  void tick();
236 
239  void drain(std::vector<VerifiedBlock>& o_out, unsigned _max);
240 
243  bool doneDrain(h256s const& _knownBad = h256s());
244 
246  void noteReady(h256 const& _b) { WriteGuard l(m_lock); noteReady_WITH_LOCK(_b); }
247 
249  void retryAllUnknown();
250 
252  std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); }
253 
255  void clear();
256 
258  void stop();
259 
261  h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
262 
264  BlockQueueStatus status() const;
265 
267  QueueStatus blockStatus(h256 const& _h) const;
268 
269  Handler<> onReady(std::function<void(void)> _t) { return m_onReady.add(_t); }
270  Handler<> onRoomAvailable(std::function<void(void)> _t) { return m_onRoomAvailable.add(_t); }
271 
272  template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
273 
274  bool knownFull() const;
275  bool unknownFull() const;
276  u256 difficulty() const; // Total difficulty of queueud blocks
277  bool isActive() const;
278 
279 private:
280  struct UnverifiedBlock
281  {
282  h256 hash;
283  h256 parentHash;
284  bytes blockData;
285  };
286 
287  void noteReady_WITH_LOCK(h256 const& _b);
288 
289  bool invariants() const override;
290 
291  void verifierBody();
292  void collectUnknownBad_WITH_BOTH_LOCKS(h256 const& _bad);
293  void updateBad_WITH_LOCK(h256 const& _bad);
294  void drainVerified_WITH_BOTH_LOCKS();
295 
296  std::size_t knownSize() const;
297  std::size_t knownCount() const;
298  std::size_t unknownSize() const;
299  std::size_t unknownCount() const;
300 
301  BlockChain const* m_bc;
302 
303  mutable boost::shared_mutex m_lock;
304  h256Hash m_drainingSet;
305  h256Hash m_readySet;
306  h256Hash m_unknownSet;
307  SizedBlockMap<h256> m_unknown;
308  h256Hash m_knownBad;
309  SizedBlockMap<time_t> m_future;
310  h256Hash m_futureSet;
311  Signal<> m_onReady;
312  Signal<> m_onRoomAvailable;
313 
314  mutable Mutex m_verification;
315  std::condition_variable m_moreToVerify;
316  SizedBlockQueue<VerifiedBlock> m_verified;
317  SizedBlockQueue<VerifiedBlock> m_verifying;
318  SizedBlockQueue<UnverifiedBlock> m_unverified;
319 
320  std::vector<std::thread> m_verifiers;
321  std::atomic<bool> m_deleting = {false};
322 
323  std::function<void(Exception&)> m_onBad;
324  u256 m_difficulty;
325  u256 m_drainingDifficulty;
326 
327  Logger m_logger{createLogger(VerbosityDebug, "bq")};
328  Logger m_loggerDetail{createLogger(VerbosityTrace, "bq")};
329 };
330 
331 std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s);
332 
333 }
334 }
dev::eth::BlockQueue::tick
void tick()
Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
Definition: BlockQueue.cpp:349
dev::eth::BlockQueue::drain
void drain(std::vector< VerifiedBlock > &o_out, unsigned _max)
Definition: BlockQueue.cpp:434
dev::eth::BlockQueue
A queue of blocks. Sits between network or other I/O and the BlockChain. Sorts them ready for blockch...
Definition: BlockQueue.h:224
dev::eth::BlockQueue::status
BlockQueueStatus status() const
Get some infomration on the current status.
Definition: BlockQueue.cpp:379
dev::eth::QueueStatus::Bad
@ Bad
dev::eth::BlockQueue::~BlockQueue
~BlockQueue()
Definition: BlockQueue.cpp:51
dev::eth::QueueStatus::UnknownParent
@ UnknownParent
dev::eth::BlockQueueStatus::importing
size_t importing
Definition: BlockQueue.h:45
dev::eth::ImportResult
ImportResult
Definition: Common.h:97
dev::vector_ref< byte const >
dev::eth::BlockQueue::noteReady
void noteReady(h256 const &_b)
Notify the queue that the chain has changed and a new block has attained 'ready' status (i....
Definition: BlockQueue.h:246
dev::eth::BlockQueueStatus::verified
size_t verified
Definition: BlockQueue.h:46
dev::eth::SizedBlockMap::count
std::size_t count() const
Definition: BlockQueue.h:159
VerifiedBlock.h
std::swap
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
Definition: Interface.h:282
dev::eth::BlockQueue::firstUnknown
h256 firstUnknown() const
Return first block with an unknown parent.
Definition: BlockQueue.h:261
dev::eth::SizedBlockMap::clear
void clear()
Definition: BlockQueue.h:167
dev::h256
FixedHash< 32 > h256
Definition: FixedHash.h:356
dev::eth::SizedBlockMap::isEmpty
bool isEmpty() const
Definition: BlockQueue.h:163
dev::eth::SizedBlockQueue::removeIf
std::vector< T > removeIf(Pred _pred)
Definition: BlockQueue.h:113
dev::eth::SizedBlockQueue::size
std::size_t size() const
Definition: BlockQueue.h:71
dev::eth::QueueStatus::Ready
@ Ready
dev::eth::BlockQueueStatus::future
size_t future
Definition: BlockQueue.h:49
BlockHeader.h
dev::FixedHash< 32 >
dev::eth::SizedBlockQueue::dequeue
T dequeue()
Definition: BlockQueue.h:91
dev::eth::QueueStatus::Importing
@ Importing
dev::eth::BlockQueue::difficulty
u256 difficulty() const
Definition: BlockQueue.cpp:530
dev::WriteGuard
boost::unique_lock< boost::shared_mutex > WriteGuard
Definition: Guards.h:47
dev::eth::BlockQueue::clear
void clear()
Clear everything.
Definition: BlockQueue.cpp:67
Common.h
dev::eth::BlockQueue::knownFull
bool knownFull() const
Definition: BlockQueue.cpp:402
dev::eth::SizedBlockQueue::count
std::size_t count() const
Definition: BlockQueue.h:69
dev::eth::BlockQueue::retryAllUnknown
void retryAllUnknown()
Force a retry of all the blocks with unknown parents.
Definition: BlockQueue.cpp:497
dev::eth::BlockQueueStatus::unknown
size_t unknown
Definition: BlockQueue.h:50
dev::h256Hash
std::unordered_set< h256 > h256Hash
Definition: FixedHash.h:365
dev::h256s
std::vector< h256 > h256s
Definition: FixedHash.h:361
dev::Logger
boost::log::sources::severity_channel_logger<> Logger
Definition: Log.h:124
dev::eth::SizedBlockMap::size
std::size_t size() const
Definition: BlockQueue.h:161
Common.h
dev::eth::SizedBlockMap::removeByKeyEqual
std::vector< std::pair< h256, bytes > > removeByKeyEqual(KeyType const &_key)
Definition: BlockQueue.h:182
dev::eth::BlockQueue::stop
void stop()
Stop all activity, leaves the class in limbo, waiting for destruction.
Definition: BlockQueue.cpp:56
dev::eth::QueueStatus
QueueStatus
Definition: BlockQueue.h:55
dev::eth::BlockQueue::blockStatus
QueueStatus blockStatus(h256 const &_h) const
Get some infomration on the given block's status regarding us.
Definition: BlockQueue.cpp:387
dev::eth::SizedBlockMap::firstKey
KeyType firstKey() const
Definition: BlockQueue.h:165
dev::eth::BlockQueueStatus
Definition: BlockQueue.h:44
dev::eth::SizedBlockMap::removeByKeyNotGreater
std::vector< std::pair< h256, bytes > > removeByKeyNotGreater(KeyType const &_key)
Definition: BlockQueue.h:189
dev::eth::BlockQueue::unknownFull
bool unknownFull() const
Definition: BlockQueue.cpp:418
dev::eth::BlockQueue::onReady
Handler onReady(std::function< void(void)> _t)
Definition: BlockQueue.h:269
dev::bytes
std::vector< byte > bytes
Definition: Common.h:72
dev::eth::BlockQueue::items
std::pair< unsigned, unsigned > items() const
Get information on the items queued.
Definition: BlockQueue.h:252
dev::createLogger
Logger createLogger(int _severity, std::string const &_channel)
Definition: Log.h:125
dev::ReadGuard
boost::shared_lock< boost::shared_mutex > ReadGuard
Definition: Guards.h:44
dev::eth::BlockChain
Implements the blockchain database. All data this gives is disk-backed. @threadsafe.
Definition: BlockChain.h:105
dev::eth::SizedBlockQueue::dequeueMultiple
std::vector< T > dequeueMultiple(std::size_t _n)
Definition: BlockQueue.h:101
dev::eth::SizedBlockQueue::remove
bool remove(h256 const &_hash)
Definition: BlockQueue.h:106
dev::eth::SizedBlockQueue::nextHash
h256 nextHash() const
Definition: BlockQueue.h:75
dev::eth::BlockQueueStatus::unverified
size_t unverified
Definition: BlockQueue.h:48
dev::eth::SizedBlockMap::insert
void insert(KeyType const &_key, h256 const &_hash, bytes &&_blockData)
Definition: BlockQueue.h:173
dev::eth::SizedBlockQueue::clear
void clear()
Definition: BlockQueue.h:79
dev::VerbosityDebug
@ VerbosityDebug
Definition: Log.h:71
dev::Mutex
std::mutex Mutex
Definition: Guards.h:37
dev::eth::BlockQueueStatus::verifying
size_t verifying
Definition: BlockQueue.h:47
dev::eth::SizedBlockQueue::next
T const & next() const
Definition: BlockQueue.h:77
dev::HasInvariants
Inheritable for classes that have invariants.
Definition: Common.h:211
dev::eth::BlockQueue::BlockQueue
BlockQueue()
Definition: BlockQueue.cpp:40
dev::u256
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
Definition: Common.h:121
dev::eth::Signal::add
std::shared_ptr< HandlerAux > add(Callback const &_h)
Definition: Common.h:162
dev::eth::operator<<
std::ostream & operator<<(std::ostream &_out, BlockHeader const &_bi)
Definition: BlockHeader.h:217
dev::eth::SizedBlockQueue
Definition: BlockQueue.h:67
dev::eth::SizedBlockQueue::isEmpty
bool isEmpty() const
Definition: BlockQueue.h:73
dev::eth::BlockQueueStatus::bad
size_t bad
Definition: BlockQueue.h:51
dev
Definition: Address.cpp:21
dev::eth::BlockQueue::setChain
void setChain(BlockChain const &_bc)
Definition: BlockQueue.h:229
dev::eth::BlockQueue::onRoomAvailable
Handler onRoomAvailable(std::function< void(void)> _t)
Definition: BlockQueue.h:270
dev::eth::QueueStatus::Unknown
@ Unknown
dev::eth::Handler
std::shared_ptr< typename Signal< Args... >::HandlerAux > Handler
Definition: Common.h:181
Guards.h
dev::eth::SizedBlockQueue::enqueue
void enqueue(T &&_t)
Definition: BlockQueue.h:85
dev::eth::BlockQueue::isActive
bool isActive() const
Definition: BlockQueue.cpp:536
dev::eth::BlockQueue::setOnBad
void setOnBad(T const &_t)
Definition: BlockQueue.h:272
dev::VerbosityTrace
@ VerbosityTrace
Definition: Log.h:72
dev::eth::BlockQueue::doneDrain
bool doneDrain(h256s const &_knownBad=h256s())
Definition: BlockQueue.cpp:332
Log.h
dev::eth::SizedBlockMap
Definition: BlockQueue.h:157
dev::eth::SizedBlockQueue::replace
bool replace(h256 const &_hash, T &&_t)
Definition: BlockQueue.h:120