Fabcoin Core  0.16.2
P2P Digital Currency
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/Common.h>
33 #include <libethcore/BlockHeader.h>
34 #include "VerifiedBlock.h"
35 
36 namespace dev
37 {
38 
39 namespace eth
40 {
41 
42 class BlockChain;
43 
44 struct BlockQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; };
45 struct BlockQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; };
46 #define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
47 
49 {
50  size_t importing;
51  size_t verified;
52  size_t verifying;
53  size_t unverified;
54  size_t future;
55  size_t unknown;
56  size_t bad;
57 };
58 
59 enum class QueueStatus
60 {
61  Ready,
62  Importing,
64  Bad,
65  Unknown
66 };
67 
68 std::ostream& operator<< (std::ostream& os, QueueStatus const& obj);
69 
70 template<class T>
72 {
73 public:
74  std::size_t count() const { return m_queue.size(); }
75 
76  std::size_t size() const { return m_size; }
77 
78  bool isEmpty() const { return m_queue.empty(); }
79 
80  h256 nextHash() const { return m_queue.front().verified.info.sha3Uncles(); }
81 
82  T const& next() const { return m_queue.front(); }
83 
84  void clear()
85  {
86  m_queue.clear();
87  m_size = 0;
88  }
89 
90  void enqueue(T&& _t)
91  {
92  m_queue.emplace_back(std::move(_t));
93  m_size += m_queue.back().blockData.size();
94  }
95 
97  {
98  T t;
99  std::swap(t, m_queue.front());
100  m_queue.pop_front();
101  m_size -= t.blockData.size();
102 
103  return t;
104  }
105 
106  std::vector<T> dequeueMultiple(std::size_t _n)
107  {
108  return removeRange(m_queue.begin(), m_queue.begin() + _n);
109  }
110 
111  bool remove(h256 const& _hash)
112  {
113  std::vector<T> removed = removeIf(sha3UnclesEquals(_hash));
114  return !removed.empty();
115  }
116 
117  template<class Pred>
118  std::vector<T> removeIf(Pred _pred)
119  {
120  auto const removedBegin = std::remove_if(m_queue.begin(), m_queue.end(), _pred);
121 
122  return removeRange(removedBegin, m_queue.end());
123  }
124 
125  bool replace(h256 const& _hash, T&& _t)
126  {
127  auto const it = std::find_if(m_queue.begin(), m_queue.end(), sha3UnclesEquals(_hash));
128 
129  if (it == m_queue.end())
130  return false;
131 
132  m_size -= it->blockData.size();
133  m_size += _t.blockData.size();
134  *it = std::move(_t);
135 
136  return true;
137  }
138 
139 private:
140  static std::function<bool(T const&)> sha3UnclesEquals(h256 const& _hash)
141  {
142  return [&_hash](T const& _t) { return _t.verified.info.sha3Uncles() == _hash; };
143  }
144 
145  std::vector<T> removeRange(typename std::deque<T>::iterator _begin, typename std::deque<T>::iterator _end)
146  {
147  std::vector<T> ret(std::make_move_iterator(_begin), std::make_move_iterator(_end));
148 
149  for (auto it = ret.begin(); it != ret.end(); ++it)
150  m_size -= it->blockData.size();
151 
152  m_queue.erase(_begin, _end);
153  return ret;
154  }
155 
156  std::deque<T> m_queue;
157  std::atomic<size_t> m_size = {0};
158 };
159 
160 template<class KeyType>
162 {
163 public:
164  std::size_t count() const { return m_map.size(); }
165 
166  std::size_t size() const { return m_size; }
167 
168  bool isEmpty() const { return m_map.empty(); }
169 
170  KeyType firstKey() const { return m_map.begin()->first; }
171 
172  void clear()
173  {
174  m_map.clear();
175  m_size = 0;
176  }
177 
178  void insert(KeyType const& _key, h256 const& _hash, bytes&& _blockData)
179  {
180  auto hashAndBlock = std::make_pair(_hash, std::move(_blockData));
181  auto keyAndValue = std::make_pair(_key, std::move(hashAndBlock));
182  m_map.insert(std::move(keyAndValue));
183  m_size += _blockData.size();
184  }
185 
186  std::vector<std::pair<h256, bytes>> removeByKeyEqual(KeyType const& _key)
187  {
188  auto const equalRange = m_map.equal_range(_key);
189  return removeRange(equalRange.first, equalRange.second);
190  }
191 
192  std::vector<std::pair<h256, bytes>> removeByKeyNotGreater(KeyType const& _key)
193  {
194  return removeRange(m_map.begin(), m_map.upper_bound(_key));
195  }
196 
197 private:
198  using BlockMultimap = std::multimap<KeyType, std::pair<h256, bytes>>;
199 
200  std::vector<std::pair<h256, bytes>> removeRange(typename BlockMultimap::iterator _begin, typename BlockMultimap::iterator _end)
201  {
202  std::vector<std::pair<h256, bytes>> removed;
203  std::size_t removedSize = 0;
204  for (auto it = _begin; it != _end; ++it)
205  {
206  removed.push_back(std::move(it->second));
207  removedSize += removed.back().second.size();
208  }
209 
210  m_size -= removedSize;
211  m_map.erase(_begin, _end);
212 
213  return removed;
214  }
215 
217  std::atomic<size_t> m_size = {0};
218 };
219 
226 {
227 public:
228  BlockQueue();
229  ~BlockQueue();
230 
231  void setChain(BlockChain const& _bc) { m_bc = &_bc; }
232 
234  ImportResult import(bytesConstRef _block, bool _isOurs = false);
235 
237  void tick();
238 
241  void drain(std::vector<VerifiedBlock>& o_out, unsigned _max);
242 
245  bool doneDrain(h256s const& _knownBad = h256s());
246 
248  void noteReady(h256 const& _b) { WriteGuard l(m_lock); noteReady_WITH_LOCK(_b); }
249 
251  void retryAllUnknown();
252 
254  std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); }
255 
257  void clear();
258 
260  void stop();
261 
263  h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
264 
266  BlockQueueStatus status() const;
267 
269  QueueStatus blockStatus(h256 const& _h) const;
270 
271  template <class T> Handler<> onReady(T const& _t) { return m_onReady.add(_t); }
272  template <class T> Handler<> onRoomAvailable(T const& _t) { return m_onRoomAvailable.add(_t); }
273 
274  template <class T> void setOnBad(T const& _t) { m_onBad = _t; }
275 
276  bool knownFull() const;
277  bool unknownFull() const;
278  u256 difficulty() const; // Total difficulty of queueud blocks
279  bool isActive() const;
280 
281 private:
283  {
287  };
288 
289  void noteReady_WITH_LOCK(h256 const& _b);
290 
291  bool invariants() const override;
292 
293  void verifierBody();
294  void collectUnknownBad_WITH_BOTH_LOCKS(h256 const& _bad);
295  void updateBad_WITH_LOCK(h256 const& _bad);
296  void drainVerified_WITH_BOTH_LOCKS();
297 
298  std::size_t knownSize() const;
299  std::size_t knownCount() const;
300  std::size_t unknownSize() const;
301  std::size_t unknownCount() const;
302 
303  BlockChain const* m_bc;
304 
305  mutable boost::shared_mutex m_lock;
314 
316  std::condition_variable m_moreToVerify;
320 
321  std::vector<std::thread> m_verifiers;
322  std::atomic<bool> m_deleting = {false};
323 
324  std::function<void(Exception&)> m_onBad;
327 };
328 
329 std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s);
330 
331 }
332 }
std::size_t count() const
Definition: BlockQueue.h:164
Inheritable for classes that have invariants.
Definition: Common.h:229
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
Super-duper signal mechanism. TODO: replace with somthing a bit heavier weight.
Definition: Common.h:133
h256Hash m_drainingSet
All blocks being imported.
Definition: BlockQueue.h:306
std::multimap< dev::FixedHash, std::pair< h256, bytes >> BlockMultimap
Definition: BlockQueue.h:198
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
Definition: Interface.h:284
Implements the blockchain database.
Definition: BlockChain.h:105
void setOnBad(T const &_t)
Definition: BlockQueue.h:274
#define T(i, x)
u256 m_drainingDifficulty
Total difficulty of blocks in draining.
Definition: BlockQueue.h:326
std::vector< T > removeRange(typename std::deque< T >::iterator _begin, typename std::deque< T >::iterator _end)
Definition: BlockQueue.h:145
std::ostream & operator<<(std::ostream &_out, BlockHeader const &_bi)
Definition: BlockHeader.h:194
BlockMultimap m_map
Definition: BlockQueue.h:216
void noteReady(h256 const &_b)
Notify the queue that the chain has changed and a new block has attained &#39;ready&#39; status (i...
Definition: BlockQueue.h:248
static const int verbosity
Definition: BlockQueue.h:44
Handler onRoomAvailable(T const &_t)
Definition: BlockQueue.h:272
h256 nextHash() const
Definition: BlockQueue.h:80
SizedBlockQueue< UnverifiedBlock > m_unverified
List of <block hash, parent hash, block data> in correct order, ready for verification.
Definition: BlockQueue.h:319
std::pair< unsigned, unsigned > items() const
Get information on the items queued.
Definition: BlockQueue.h:254
std::size_t size() const
Definition: BlockQueue.h:166
SizedBlockQueue< VerifiedBlock > m_verifying
List of blocks being verified; as long as the block component (bytes) is empty, it&#39;s not finished...
Definition: BlockQueue.h:318
std::vector< std::thread > m_verifiers
Threads who only verify.
Definition: BlockQueue.h:321
h256Hash m_readySet
All blocks ready for chain import.
Definition: BlockQueue.h:307
concurrent_queue< JitTask > m_queue
Definition: SmartVM.cpp:60
Mutex m_verification
Mutex that allows writing to m_verified, m_verifying and m_unverified.
Definition: BlockQueue.h:315
SizedBlockMap< time_t > m_future
Set of blocks that are not yet valid. Ordered by timestamp.
Definition: BlockQueue.h:311
ImportResult
Definition: Common.h:97
Signal m_onRoomAvailable
Called when space for new blocks becomes availabe after a drain. Be nice and exit fast...
Definition: BlockQueue.h:313
std::vector< std::pair< h256, bytes > > removeRange(typename BlockMultimap::iterator _begin, typename BlockMultimap::iterator _end)
Definition: BlockQueue.h:200
void insert(KeyType const &_key, h256 const &_hash, bytes &&_blockData)
Definition: BlockQueue.h:178
T const & next() const
Definition: BlockQueue.h:82
std::shared_ptr< typename Signal< Args... >::HandlerAux > Handler
Definition: Common.h:181
std::deque< T > m_queue
Definition: BlockQueue.h:156
std::vector< byte > bytes
Definition: Common.h:75
FixedHash< 32 > h256
Definition: FixedHash.h:340
A queue of blocks.
Definition: BlockQueue.h:225
h256 firstUnknown() const
Return first block with an unknown parent.
Definition: BlockQueue.h:263
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
std::vector< std::pair< h256, bytes > > removeByKeyEqual(KeyType const &_key)
Definition: BlockQueue.h:186
boost::shared_lock< boost::shared_mutex > ReadGuard
Definition: Guards.h:44
h256Hash m_unknownSet
Set of all blocks whose parents are not ready/in-chain.
Definition: BlockQueue.h:308
Signal m_onReady
Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fa...
Definition: BlockQueue.h:312
std::vector< std::pair< h256, bytes > > removeByKeyNotGreater(KeyType const &_key)
Definition: BlockQueue.h:192
boost::unique_lock< boost::shared_mutex > WriteGuard
Definition: Guards.h:47
KeyType firstKey() const
Definition: BlockQueue.h:170
static std::function< bool(T const &)> sha3UnclesEquals(h256 const &_hash)
Definition: BlockQueue.h:140
std::vector< T > dequeueMultiple(std::size_t _n)
Definition: BlockQueue.h:106
Handler onReady(T const &_t)
Definition: BlockQueue.h:271
std::condition_variable m_moreToVerify
Signaled when m_unverified has a new entry.
Definition: BlockQueue.h:316
u256 m_difficulty
Total difficulty of blocks in the queue.
Definition: BlockQueue.h:325
boost::shared_mutex m_lock
General lock for the sets, m_future and m_unknown.
Definition: BlockQueue.h:305
void setChain(BlockChain const &_bc)
Definition: BlockQueue.h:231
bool replace(h256 const &_hash, T &&_t)
Definition: BlockQueue.h:125
BlockChain const * m_bc
The blockchain into which our imports go.
Definition: BlockQueue.h:303
The default logging channels.
Definition: Log.h:130
SizedBlockQueue< VerifiedBlock > m_verified
List of blocks, in correct order, verified and ready for chain-import.
Definition: BlockQueue.h:317
std::unordered_set< h256 > h256Hash
Definition: FixedHash.h:349
h256Hash m_knownBad
Set of blocks that we know will never be valid.
Definition: BlockQueue.h:310
std::mutex Mutex
Definition: Guards.h:37
bool isEmpty() const
Definition: BlockQueue.h:168
std::vector< h256 > h256s
Definition: FixedHash.h:345
static const char * name()
Definition: BlockQueue.cpp:38
bool isEmpty() const
Definition: BlockQueue.h:78
std::size_t size() const
Definition: BlockQueue.h:76
std::vector< T > removeIf(Pred _pred)
Definition: BlockQueue.h:118
std::function< void(Exception &)> m_onBad
Called if we have a block that doesn&#39;t verify.
Definition: BlockQueue.h:324
SizedBlockMap< h256 > m_unknown
For blocks that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
Definition: BlockQueue.h:309
UniValue stop(const JSONRPCRequest &jsonRequest)
Definition: server.cpp:237
std::size_t count() const
Definition: BlockQueue.h:74