47 BlockQueue::BlockQueue()
50 unsigned verifierThreads =
std::max(thread::hardware_concurrency(), 3U) - 2U;
51 for (
unsigned i = 0; i < verifierThreads; ++i)
52 m_verifiers.emplace_back([=](){
53 setThreadName(
"verifier" + toString(i));
58 BlockQueue::~BlockQueue()
68 m_moreToVerify.notify_all();
69 for (
auto& i: m_verifiers)
74 void BlockQueue::clear()
78 Guard l2(m_verification);
80 m_drainingSet.clear();
88 m_drainingDifficulty = 0;
91 void BlockQueue::verifierBody()
98 unique_lock<Mutex> l(m_verification);
99 m_moreToVerify.wait(l, [&](){
return !m_unverified.isEmpty() || m_deleting; });
102 work = m_unverified.dequeue();
107 m_verifying.enqueue(move(bi));
114 res.
verified = m_bc->verifyBlock(&res.
blockData, m_onBad, ImportRequirements::OutOfOrderChecks);
116 catch (std::exception
const& _ex)
121 unique_lock<Mutex> l(m_verification);
122 m_readySet.erase(work.
hash);
123 m_knownBad.insert(work.
hash);
124 if (!m_verifying.remove(work.
hash))
125 cwarn <<
"Unexpected exception when verifying block: " << _ex.what();
126 drainVerified_WITH_BOTH_LOCKS();
133 unique_lock<Mutex> l(m_verification);
134 if (!m_verifying.isEmpty() && m_verifying.nextHash() == work.
hash)
137 m_verifying.dequeue();
144 m_verified.enqueue(move(res));
146 drainVerified_WITH_BOTH_LOCKS();
151 if (!m_verifying.replace(work.
hash, move(res)))
152 cwarn <<
"BlockQueue missing our job: was there a GM?";
160 void BlockQueue::drainVerified_WITH_BOTH_LOCKS()
162 while (!m_verifying.isEmpty() && !m_verifying.next().blockData.empty())
171 m_verified.enqueue(move(block));
179 h256 h = BlockHeader::headerHashFromBlock(_block);
185 if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h))
189 return ImportResult::AlreadyKnown;
197 bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::PostGenesis).info;
201 cwarn <<
"Ignoring malformed block: " << diagnostic_information(_e);
202 return ImportResult::Malformed;
208 if (m_bc->isKnown(h))
210 cblockq <<
"Already known in chain.";
211 return ImportResult::AlreadyInChain;
222 time_t bit =
static_cast<time_t
>(bi.
timestamp());
223 if (strftime(buf, 24,
"%X", localtime(&bit)) == 0)
228 return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown;
235 m_knownBad.insert(bi.
hash());
236 updateBad_WITH_LOCK(bi.
hash());
238 return ImportResult::BadChain;
245 m_unknownSet.insert(h);
248 return ImportResult::UnknownParent;
256 m_moreToVerify.notify_one();
257 m_readySet.insert(h);
260 noteReady_WITH_LOCK(h);
262 return ImportResult::Success;
267 void BlockQueue::updateBad_WITH_LOCK(
h256 const& _bad)
272 collectUnknownBad_WITH_BOTH_LOCKS(_bad);
277 std::vector<VerifiedBlock> badVerified = m_verified.removeIf([
this](
VerifiedBlock const& _b)
281 for (
auto&
b: badVerified)
283 m_knownBad.insert(
b.verified.info.hash());
284 m_readySet.erase(
b.verified.info.hash());
285 collectUnknownBad_WITH_BOTH_LOCKS(
b.verified.info.hash());
289 std::vector<UnverifiedBlock> badUnverified = m_unverified.removeIf([
this](
UnverifiedBlock const& _b)
291 return m_knownBad.count(_b.
parentHash) || m_knownBad.count(_b.
hash);
293 for (
auto&
b: badUnverified)
295 m_knownBad.insert(
b.hash);
296 m_readySet.erase(
b.hash);
297 collectUnknownBad_WITH_BOTH_LOCKS(
b.hash);
301 std::vector<VerifiedBlock> badVerifying = m_verifying.removeIf([
this](
VerifiedBlock const& _b)
305 for (
auto&
b: badVerifying)
307 h256 const&
h =
b.blockData.size() != 0 ?
b.verified.info.hash() :
b.verified.info.sha3Uncles();
308 m_knownBad.insert(h);
310 collectUnknownBad_WITH_BOTH_LOCKS(h);
317 void BlockQueue::collectUnknownBad_WITH_BOTH_LOCKS(
h256 const& _bad)
319 list<h256> badQueue(1, _bad);
320 while (!badQueue.empty())
322 vector<pair<h256, bytes>>
const removed = m_unknown.removeByKeyEqual(badQueue.front());
323 badQueue.pop_front();
324 for (
auto& newBad: removed)
326 m_unknownSet.erase(newBad.first);
327 m_knownBad.insert(newBad.first);
328 badQueue.push_back(newBad.first);
333 bool BlockQueue::doneDrain(
h256s const& _bad)
337 m_drainingSet.clear();
338 m_difficulty -= m_drainingDifficulty;
339 m_drainingDifficulty = 0;
344 for (
h256 const&
b: _bad)
345 updateBad_WITH_LOCK(
b);
347 return !m_readySet.empty();
350 void BlockQueue::tick()
352 vector<pair<h256, bytes>> todo;
355 if (m_future.isEmpty())
358 cblockq <<
"Checking past-future blocks...";
361 if (t < m_future.firstKey())
364 cblockq <<
"Past-future blocks ready.";
369 todo = m_future.removeByKeyNotGreater(t);
372 cblockq <<
"Importing" << todo.size() <<
"past-future blocks.";
374 for (
auto const&
b: todo)
381 Guard l2(m_verification);
382 return BlockQueueStatus{ m_drainingSet.size(), m_verified.count(), m_verifying.count(), m_unverified.count(),
383 m_future.count(), m_unknown.count(), m_knownBad.size() };
390 m_readySet.count(_h) ?
392 m_drainingSet.count(_h) ?
393 QueueStatus::Importing :
394 m_unknownSet.count(_h) ?
395 QueueStatus::UnknownParent :
396 m_knownBad.count(_h) ?
398 QueueStatus::Unknown;
401 bool BlockQueue::knownFull()
const 403 Guard l(m_verification);
407 std::size_t BlockQueue::knownSize()
const 409 return m_verified.size() + m_unverified.size() + m_verifying.size();
412 std::size_t BlockQueue::knownCount()
const 414 return m_verified.count() + m_unverified.count() + m_verifying.count();
417 bool BlockQueue::unknownFull()
const 423 std::size_t BlockQueue::unknownSize()
const 425 return m_future.size() + m_unknown.size();
428 std::size_t BlockQueue::unknownCount()
const 430 return m_future.count() + m_unknown.count();
435 bool wasFull =
false;
439 wasFull = knownFull();
440 if (m_drainingSet.empty())
442 m_drainingDifficulty = 0;
444 o_out = m_verified.dequeueMultiple(min<unsigned>(_max, m_verified.count()));
446 for (
auto const& bs: o_out)
449 auto h = bs.verified.info.hash();
450 m_drainingSet.insert(
h);
451 m_drainingDifficulty += bs.verified.info.difficulty();
456 if (wasFull && !knownFull())
460 bool BlockQueue::invariants()
const 462 Guard l(m_verification);
463 if (m_readySet.size() != knownCount())
466 s <<
"Failed BlockQueue invariant: m_readySet: " << m_readySet.size() <<
" m_verified: " << m_verified.count() <<
" m_unverified: " << m_unverified.count() <<
" m_verifying" << m_verifying.count();
472 void BlockQueue::noteReady_WITH_LOCK(
h256 const& _good)
475 list<h256> goodQueue(1, _good);
477 while (!goodQueue.empty())
479 h256 const parent = goodQueue.front();
480 vector<pair<h256, bytes>>
const removed = m_unknown.removeByKeyEqual(parent);
481 goodQueue.pop_front();
482 for (
auto& newReady: removed)
485 m_unverified.enqueue(
UnverifiedBlock { newReady.first, parent, move(newReady.second) });
486 m_unknownSet.erase(newReady.first);
487 m_readySet.insert(newReady.first);
488 goodQueue.push_back(newReady.first);
493 m_moreToVerify.notify_all();
496 void BlockQueue::retryAllUnknown()
500 while (!m_unknown.isEmpty())
502 h256 parent = m_unknown.firstKey();
503 vector<pair<h256, bytes>> removed = m_unknown.removeByKeyEqual(parent);
504 for (
auto& newReady: removed)
507 m_unverified.enqueue(
UnverifiedBlock{ newReady.first, parent, move(newReady.second) });
508 m_unknownSet.erase(newReady.first);
509 m_readySet.insert(newReady.first);
510 m_moreToVerify.notify_one();
513 m_moreToVerify.notify_all();
518 _out <<
"importing: " << _bqs.
importing << endl;
519 _out <<
"verified: " << _bqs.
verified << endl;
520 _out <<
"verifying: " << _bqs.
verifying << endl;
521 _out <<
"unverified: " << _bqs.
unverified << endl;
522 _out <<
"future: " << _bqs.
future << endl;
523 _out <<
"unknown: " << _bqs.
unknown << endl;
524 _out <<
"bad: " << _bqs.
bad << endl;
529 u256 BlockQueue::difficulty()
const 535 bool BlockQueue::isActive()
const 538 if (m_readySet.empty() && m_drainingSet.empty())
540 if (m_verified.isEmpty() && m_verifying.isEmpty() && m_unverified.isEmpty())
size_t const c_maxUnknownCount
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
uint64_t utcTime()
Get the current time in seconds since the epoch in UTC.
std::ostream & operator<<(std::ostream &_out, BlockHeader const &_bi)
boost::upgrade_to_unique_lock< boost::shared_mutex > UpgradeGuard
std::hash for asio::adress
boost::upgrade_lock< boost::shared_mutex > UpgradableGuard
VerifiedBlockRef verified
Verified block structures.
Verified block info, combines block data and verified info/transactions.
#define DEV_GUARDED(MUTEX)
Simple block guard.
#define DEV_INVARIANT_CHECK
Scope guard for invariant check in a class derived from HasInvariants.
Base class for all exceptions.
std::lock_guard< std::mutex > Guard
#define DEV_WRITE_GUARDED(MUTEX)
std::vector< unsigned char > toBytes() const
bytes blockData
Block data.
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
boost::shared_lock< boost::shared_mutex > ReadGuard
boost::unique_lock< boost::shared_mutex > WriteGuard
size_t const c_maxKnownSize
size_t const c_maxKnownCount
PlatformStyle::TableColorType type
boost::error_info< struct tag_comment, std::string > errinfo_comment
std::vector< VerifiedBlock > VerifiedBlocks
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
std::vector< h256 > h256s
BlockHeader info
Prepopulated block info.
UniValue stop(const JSONRPCRequest &jsonRequest)
size_t const c_maxUnknownSize