Fabcoin Core  0.16.2
P2P Digital Currency
BlockChainSync.cpp
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 #include "BlockChainSync.h"
23 
24 #include <chrono>
25 #include <libdevcore/Common.h>
26 #include <libdevcore/TrieHash.h>
27 #include <libp2p/Host.h>
28 #include <libp2p/Session.h>
29 #include <libethcore/Exceptions.h>
30 #include "BlockChain.h"
31 #include "BlockQueue.h"
32 #include "EthereumPeer.h"
33 #include "EthereumHost.h"
34 
35 using namespace std;
36 using namespace dev;
37 using namespace dev::eth;
38 using namespace p2p;
39 
40 unsigned const c_maxPeerUknownNewBlocks = 1024;
41 unsigned const c_maxRequestHeaders = 1024;
42 unsigned const c_maxRequestBodies = 1024;
43 
44 
45 std::ostream& dev::eth::operator<<(std::ostream& _out, SyncStatus const& _sync)
46 {
47  _out << "protocol: " << _sync.protocolVersion << endl;
48  _out << "state: " << EthereumHost::stateName(_sync.state) << " ";
49  if (_sync.state == SyncState::Blocks || _sync.state == SyncState::NewBlocks)
50  _out << _sync.currentBlockNumber << "/" << _sync.highestBlockNumber;
51  return _out;
52 }
53 
54 namespace // Helper functions.
55 {
56 
57 template<typename T> bool haveItem(std::map<unsigned, T>& _container, unsigned _number)
58 {
59  if (_container.empty())
60  return false;
61  auto lower = _container.lower_bound(_number);
62  if (lower != _container.end() && lower->first == _number)
63  return true;
64  if (lower == _container.begin())
65  return false;
66  --lower;
67  return lower->first <= _number && (lower->first + lower->second.size()) > _number;
68 }
69 
70 template<typename T> T const* findItem(std::map<unsigned, std::vector<T>>& _container, unsigned _number)
71 {
72  if (_container.empty())
73  return nullptr;
74  auto lower = _container.lower_bound(_number);
75  if (lower != _container.end() && lower->first == _number)
76  return &(*lower->second.begin());
77  if (lower == _container.begin())
78  return nullptr;
79  --lower;
80  if (lower->first <= _number && (lower->first + lower->second.size()) > _number)
81  return &lower->second.at(_number - lower->first);
82  return nullptr;
83 }
84 
85 template<typename T> void removeItem(std::map<unsigned, std::vector<T>>& _container, unsigned _number)
86 {
87  if (_container.empty())
88  return;
89  auto lower = _container.lower_bound(_number);
90  if (lower != _container.end() && lower->first == _number)
91  {
92  _container.erase(lower);
93  return;
94  }
95  if (lower == _container.begin())
96  return;
97  --lower;
98  if (lower->first <= _number && (lower->first + lower->second.size()) > _number)
99  lower->second.erase(lower->second.begin() + (_number - lower->first), lower->second.end());
100 }
101 
102 template<typename T> void removeAllStartingWith(std::map<unsigned, std::vector<T>>& _container, unsigned _number)
103 {
104  if (_container.empty())
105  return;
106  auto lower = _container.lower_bound(_number);
107  if (lower != _container.end() && lower->first == _number)
108  {
109  _container.erase(lower, _container.end());
110  return;
111  }
112  if (lower == _container.begin())
113  {
114  _container.clear();
115  return;
116  }
117  --lower;
118  if (lower->first <= _number && (lower->first + lower->second.size()) > _number)
119  lower->second.erase(lower->second.begin() + (_number - lower->first), lower->second.end());
120  _container.erase(++lower, _container.end());
121 }
122 
123 template<typename T> void mergeInto(std::map<unsigned, std::vector<T>>& _container, unsigned _number, T&& _data)
124 {
125  assert(!haveItem(_container, _number));
126  auto lower = _container.lower_bound(_number);
127  if (!_container.empty() && lower != _container.begin())
128  --lower;
129  if (lower != _container.end() && (lower->first + lower->second.size() == _number))
130  {
131  // extend existing chunk
132  lower->second.emplace_back(_data);
133 
134  auto next = lower;
135  ++next;
136  if (next != _container.end() && (lower->first + lower->second.size() == next->first))
137  {
138  // merge with the next chunk
139  std::move(next->second.begin(), next->second.end(), std::back_inserter(lower->second));
140  _container.erase(next);
141  }
142 
143  }
144  else
145  {
146  // insert a new chunk
147  auto inserted = _container.insert(lower, std::make_pair(_number, std::vector<T> { _data }));
148  auto next = inserted;
149  ++next;
150  if (next != _container.end() && next->first == _number + 1)
151  {
152  std::move(next->second.begin(), next->second.end(), std::back_inserter(inserted->second));
153  _container.erase(next);
154  }
155  }
156 }
157 
158 } // Anonymous namespace -- helper functions.
159 
160 BlockChainSync::BlockChainSync(EthereumHost& _host):
161  m_host(_host),
162  m_startingBlock(_host.chain().number()),
163  m_lastImportedBlock(m_startingBlock),
164  m_lastImportedBlockHash(_host.chain().currentHash())
165 {
167  {
170  continueSync();
171  });
172 }
173 
175 {
177  abortSync();
178 }
179 
181 {
182  //if a block has been added via mining or other block import function
183  //through RPC, then we should count it as a last imported block
185  if (_info.number() > m_lastImportedBlock)
186  {
187  m_lastImportedBlock = static_cast<unsigned>(_info.number());
188  m_lastImportedBlockHash = _info.hash();
190  }
191 }
192 
194 {
195  resetSync();
196  host().foreachPeer([&](std::shared_ptr<EthereumPeer> _p)
197  {
198  _p->abortSync();
199  return true;
200  });
201 }
202 
203 void BlockChainSync::onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
204 {
207  std::shared_ptr<SessionFace> session = _peer->session();
208  if (!session)
209  return; // Expired
210  if (_peer->m_genesisHash != host().chain().genesisHash())
211  _peer->disable("Invalid genesis hash");
212  else if (_peer->m_protocolVersion != host().protocolVersion() && _peer->m_protocolVersion != EthereumHost::c_oldProtocolVersion)
213  _peer->disable("Invalid protocol version.");
214  else if (_peer->m_networkId != host().networkId())
215  _peer->disable("Invalid network identifier.");
216  else if (session->info().clientVersion.find("/v0.7.0/") != string::npos)
217  _peer->disable("Blacklisted client version.");
218  else if (host().isBanned(session->id()))
219  _peer->disable("Peer banned for previous bad behaviour.");
220  else if (_peer->m_asking != Asking::State && _peer->m_asking != Asking::Nothing)
221  _peer->disable("Peer banned for unexpected status message.");
222  else
223  syncPeer(_peer, false);
224 }
225 
226 void BlockChainSync::syncPeer(std::shared_ptr<EthereumPeer> _peer, bool _force)
227 {
228  if (_peer->m_asking != Asking::Nothing)
229  {
230  clog(NetAllDetail) << "Can't sync with this peer - outstanding asks.";
231  return;
232  }
233 
235  return;
236 
238  if (host().bq().isActive())
239  td += host().bq().difficulty();
240 
241  u256 syncingDifficulty = std::max(m_syncingTotalDifficulty, td);
242 
243  if (_force || _peer->m_totalDifficulty > syncingDifficulty)
244  {
245  // start sync
246  m_syncingTotalDifficulty = _peer->m_totalDifficulty;
249  _peer->requestBlockHeaders(_peer->m_latestHash, 1, 0, false);
250  _peer->m_requireTransactions = true;
251  return;
252  }
253 
254  if (m_state == SyncState::Blocks)
255  {
256  requestBlocks(_peer);
257  return;
258  }
259 }
260 
262 {
263  host().foreachPeer([this](std::shared_ptr<EthereumPeer> _p)
264  {
265  syncPeer(_p, false);
266  return true;
267  });
268 }
269 
270 void BlockChainSync::requestBlocks(std::shared_ptr<EthereumPeer> _peer)
271 {
272  clearPeerDownload(_peer);
273  if (host().bq().knownFull())
274  {
275  clog(NetAllDetail) << "Waiting for block queue before downloading blocks";
276  pauseSync();
277  return;
278  }
279  // check to see if we need to download any block bodies first
280  auto header = m_headers.begin();
281  h256s neededBodies;
282  vector<unsigned> neededNumbers;
283  unsigned index = 0;
284  if (m_haveCommonHeader && !m_headers.empty() && m_headers.begin()->first == m_lastImportedBlock + 1)
285  {
286  while (header != m_headers.end() && neededBodies.size() < c_maxRequestBodies && index < header->second.size())
287  {
288  unsigned block = header->first + index;
289  if (m_downloadingBodies.count(block) == 0 && !haveItem(m_bodies, block))
290  {
291  neededBodies.push_back(header->second[index].hash);
292  neededNumbers.push_back(block);
293  m_downloadingBodies.insert(block);
294  }
295 
296  ++index;
297  if (index >= header->second.size())
298  break; // Download bodies only for validated header chain
299  }
300  }
301  if (neededBodies.size() > 0)
302  {
303  m_bodySyncPeers[_peer] = neededNumbers;
304  _peer->requestBlockBodies(neededBodies);
305  }
306  else
307  {
308  // check if need to download headers
309  unsigned start = 0;
310  if (!m_haveCommonHeader)
311  {
312  // download backwards until common block is found 1 header at a time
313  start = m_lastImportedBlock;
314  if (!m_headers.empty())
315  start = std::min(start, m_headers.begin()->first - 1);
316  m_lastImportedBlock = start;
318 
319  if (start <= 1)
320  m_haveCommonHeader = true; //reached genesis
321  }
322  if (m_haveCommonHeader)
323  {
324  start = m_lastImportedBlock + 1;
325  auto next = m_headers.begin();
326  unsigned count = 0;
327  if (!m_headers.empty() && start >= m_headers.begin()->first)
328  {
329  start = m_headers.begin()->first + m_headers.begin()->second.size();
330  ++next;
331  }
332 
333  while (count == 0 && next != m_headers.end())
334  {
335  count = std::min(c_maxRequestHeaders, next->first - start);
336  while(count > 0 && m_downloadingHeaders.count(start) != 0)
337  {
338  start++;
339  count--;
340  }
341  std::vector<unsigned> headers;
342  for (unsigned block = start; block < start + count; block++)
343  if (m_downloadingHeaders.count(block) == 0)
344  {
345  headers.push_back(block);
346  m_downloadingHeaders.insert(block);
347  }
348  count = headers.size();
349  if (count > 0)
350  {
351  m_headerSyncPeers[_peer] = headers;
352  assert(!haveItem(m_headers, start));
353  _peer->requestBlockHeaders(start, count, 0, false);
354  }
355  else if (start >= next->first)
356  {
357  start = next->first + next->second.size();
358  ++next;
359  }
360  }
361  }
362  else
363  _peer->requestBlockHeaders(start, 1, 0, false);
364  }
365 }
366 
367 void BlockChainSync::clearPeerDownload(std::shared_ptr<EthereumPeer> _peer)
368 {
369  auto syncPeer = m_headerSyncPeers.find(_peer);
370  if (syncPeer != m_headerSyncPeers.end())
371  {
372  for (unsigned block : syncPeer->second)
373  m_downloadingHeaders.erase(block);
375  }
376  syncPeer = m_bodySyncPeers.find(_peer);
377  if (syncPeer != m_bodySyncPeers.end())
378  {
379  for (unsigned block : syncPeer->second)
380  m_downloadingBodies.erase(block);
381  m_bodySyncPeers.erase(syncPeer);
382  }
383 }
384 
386 {
387  for (auto s = m_headerSyncPeers.begin(); s != m_headerSyncPeers.end();)
388  {
389  if (s->first.expired())
390  {
391  for (unsigned block : s->second)
392  m_downloadingHeaders.erase(block);
393  m_headerSyncPeers.erase(s++);
394  }
395  else
396  ++s;
397  }
398  for (auto s = m_bodySyncPeers.begin(); s != m_bodySyncPeers.end();)
399  {
400  if (s->first.expired())
401  {
402  for (unsigned block : s->second)
403  m_downloadingBodies.erase(block);
404  m_bodySyncPeers.erase(s++);
405  }
406  else
407  ++s;
408  }
409 }
410 
412 {
414  clog(NetNote) << "NewBlock: " << _h;
415  m_knownNewHashes.erase(_h);
416 }
417 
418 void BlockChainSync::onPeerBlockHeaders(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
419 {
422  size_t itemCount = _r.itemCount();
423  clog(NetMessageSummary) << "BlocksHeaders (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreHeaders");
424  clearPeerDownload(_peer);
426  {
427  clog(NetMessageSummary) << "Ignoring unexpected blocks";
428  return;
429  }
431  {
432  clog(NetAllDetail) << "Ignored blocks while waiting";
433  return;
434  }
435  if (itemCount == 0)
436  {
437  clog(NetAllDetail) << "Peer does not have the blocks requested";
438  _peer->addRating(-1);
439  }
440  for (unsigned i = 0; i < itemCount; i++)
441  {
442  BlockHeader info(_r[i].data(), HeaderData);
443  unsigned blockNumber = static_cast<unsigned>(info.number());
444  if (haveItem(m_headers, blockNumber))
445  {
446  clog(NetMessageSummary) << "Skipping header " << blockNumber;
447  continue;
448  }
449  if (blockNumber <= m_lastImportedBlock && m_haveCommonHeader)
450  {
451  clog(NetMessageSummary) << "Skipping header " << blockNumber;
452  continue;
453  }
454  if (blockNumber > m_highestBlock)
455  m_highestBlock = blockNumber;
456 
457  auto status = host().bq().blockStatus(info.hash());
459  {
460  m_haveCommonHeader = true;
461  m_lastImportedBlock = (unsigned)info.number();
462  m_lastImportedBlockHash = info.hash();
463  }
464  else
465  {
466  Header hdr { _r[i].data().toBytes(), info.hash(), info.parentHash() };
467 
468  // validate chain
469  HeaderId headerId { info.transactionsRoot(), info.sha3Uncles() };
470  if (m_haveCommonHeader)
471  {
472  Header const* prevBlock = findItem(m_headers, blockNumber - 1);
473  if ((prevBlock && prevBlock->hash != info.parentHash()) || (blockNumber == m_lastImportedBlock + 1 && info.parentHash() != m_lastImportedBlockHash))
474  {
475  // mismatching parent id, delete the previous block and don't add this one
476  clog(NetImpolite) << "Unknown block header " << blockNumber << " " << info.hash() << " (Restart syncing)";
477  _peer->addRating(-1);
478  restartSync();
479  return ;
480  }
481 
482  Header const* nextBlock = findItem(m_headers, blockNumber + 1);
483  if (nextBlock && nextBlock->parent != info.hash())
484  {
485  clog(NetImpolite) << "Unknown block header " << blockNumber + 1 << " " << nextBlock->hash;
486  // clear following headers
487  unsigned n = blockNumber + 1;
488  auto headers = m_headers.at(n);
489  for (auto const& h : headers)
490  {
491  BlockHeader deletingInfo(h.data, HeaderData);
492  m_headerIdToNumber.erase(headerId);
493  m_downloadingBodies.erase(n);
494  m_downloadingHeaders.erase(n);
495  ++n;
496  }
497  removeAllStartingWith(m_headers, blockNumber + 1);
498  removeAllStartingWith(m_bodies, blockNumber + 1);
499  }
500  }
501 
502  mergeInto(m_headers, blockNumber, std::move(hdr));
503  if (headerId.transactionsRoot == EmptyTrie && headerId.uncles == EmptyListSHA3)
504  {
505  //empty body, just mark as downloaded
506  RLPStream r(2);
509  bytes body;
510  r.swapOut(body);
511  mergeInto(m_bodies, blockNumber, std::move(body));
512  }
513  else
514  m_headerIdToNumber[headerId] = blockNumber;
515  }
516  }
517  collectBlocks();
518  continueSync();
519 }
520 
521 void BlockChainSync::onPeerBlockBodies(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
522 {
525  size_t itemCount = _r.itemCount();
526  clog(NetMessageSummary) << "BlocksBodies (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBodies");
527  clearPeerDownload(_peer);
529  clog(NetMessageSummary) << "Ignoring unexpected blocks";
530  return;
531  }
533  {
534  clog(NetAllDetail) << "Ignored blocks while waiting";
535  return;
536  }
537  if (itemCount == 0)
538  {
539  clog(NetAllDetail) << "Peer does not have the blocks requested";
540  _peer->addRating(-1);
541  }
542  for (unsigned i = 0; i < itemCount; i++)
543  {
544  RLP body(_r[i]);
545 
546  auto txList = body[0];
547  h256 transactionRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); });
548  h256 uncles = sha3(body[1].data());
549  HeaderId id { transactionRoot, uncles };
550  auto iter = m_headerIdToNumber.find(id);
551  if (iter == m_headerIdToNumber.end() || !haveItem(m_headers, iter->second))
552  {
553  clog(NetAllDetail) << "Ignored unknown block body";
554  continue;
555  }
556  unsigned blockNumber = iter->second;
557  if (haveItem(m_bodies, blockNumber))
558  {
559  clog(NetMessageSummary) << "Skipping already downloaded block body " << blockNumber;
560  continue;
561  }
562  m_headerIdToNumber.erase(id);
563  mergeInto(m_bodies, blockNumber, body.data().toBytes());
564  }
565  collectBlocks();
566  continueSync();
567 }
568 
570 {
571  if (!m_haveCommonHeader || m_headers.empty() || m_bodies.empty())
572  return;
573 
574  // merge headers and bodies
575  auto& headers = *m_headers.begin();
576  auto& bodies = *m_bodies.begin();
577  if (headers.first != bodies.first || headers.first != m_lastImportedBlock + 1)
578  return;
579 
580  unsigned success = 0;
581  unsigned future = 0;
582  unsigned got = 0;
583  unsigned unknown = 0;
584  size_t i = 0;
585  for (; i < headers.second.size() && i < bodies.second.size(); i++)
586  {
587  RLPStream blockStream(3);
588  blockStream.appendRaw(headers.second[i].data);
589  RLP body(bodies.second[i]);
590  blockStream.appendRaw(body[0].data());
591  blockStream.appendRaw(body[1].data());
592  bytes block;
593  blockStream.swapOut(block);
594  switch (host().bq().import(&block))
595  {
597  success++;
598  if (headers.first + i > m_lastImportedBlock)
599  {
600  m_lastImportedBlock = headers.first + (unsigned)i;
601  m_lastImportedBlockHash = headers.second[i].hash;
602  }
603  break;
606  restartSync();
607  return;
608 
610  future++;
611  break;
613  break;
617  if (headers.first + i > m_lastImportedBlock)
618  {
619  resetSync();
620  m_haveCommonHeader = false; // fork detected, search for common header again
621  }
622  return;
623 
624  default:;
625  }
626  }
627 
628  clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known received.";
629 
630  if (host().bq().unknownFull())
631  {
632  clog(NetWarn) << "Too many unknown blocks, restarting sync";
633  restartSync();
634  return;
635  }
636 
637  auto newHeaders = std::move(headers.second);
638  newHeaders.erase(newHeaders.begin(), newHeaders.begin() + i);
639  unsigned newHeaderHead = headers.first + i;
640  auto newBodies = std::move(bodies.second);
641  newBodies.erase(newBodies.begin(), newBodies.begin() + i);
642  unsigned newBodiesHead = bodies.first + i;
643  m_headers.erase(m_headers.begin());
644  m_bodies.erase(m_bodies.begin());
645  if (!newHeaders.empty())
646  m_headers[newHeaderHead] = newHeaders;
647  if (!newBodies.empty())
648  m_bodies[newBodiesHead] = newBodies;
649 
650  if (m_headers.empty())
651  {
652  assert(m_bodies.empty());
653  completeSync();
654  }
656 }
657 
658 void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP const& _r)
659 {
662 
663  if (_r.itemCount() != 2)
664  {
665  _peer->disable("NewBlock without 2 data fields.");
666  return;
667  }
668  BlockHeader info(_r[0][0].data(), HeaderData);
669  auto h = info.hash();
670  DEV_GUARDED(_peer->x_knownBlocks)
671  _peer->m_knownBlocks.insert(h);
672  unsigned blockNumber = static_cast<unsigned>(info.number());
673  if (blockNumber > (m_lastImportedBlock + 1))
674  {
675  clog(NetAllDetail) << "Received unknown new block";
676  syncPeer(_peer, true);
677  return;
678  }
679  switch (host().bq().import(_r[0].data()))
680  {
682  _peer->addRating(100);
683  logNewBlock(h);
684  if (blockNumber > m_lastImportedBlock)
685  {
688  }
690  m_downloadingBodies.erase(blockNumber);
691  m_downloadingHeaders.erase(blockNumber);
692  removeItem(m_headers, blockNumber);
693  removeItem(m_bodies, blockNumber);
694  if (m_headers.empty())
695  {
696  if (!m_bodies.empty())
697  {
698  clog(NetMessageDetail) << "Block headers map is empty, but block bodies map is not. Force-clearing.";
699  m_bodies.clear();
700  }
701  completeSync();
702  }
703  break;
705  //TODO: Rating dependent on how far in future it is.
706  break;
707 
710  logNewBlock(h);
711  _peer->disable("Malformed block received.");
712  return;
713 
716  break;
717 
720  {
721  _peer->m_unknownNewBlocks++;
722  if (_peer->m_unknownNewBlocks > c_maxPeerUknownNewBlocks)
723  {
724  _peer->disable("Too many uknown new blocks");
725  restartSync();
726  }
727  logNewBlock(h);
728  u256 totalDifficulty = _r[1].toInt<u256>();
729  if (totalDifficulty > _peer->m_totalDifficulty)
730  {
731  clog(NetMessageDetail) << "Received block with no known parent. Peer needs syncing...";
732  syncPeer(_peer, true);
733  }
734  break;
735  }
736  default:;
737  }
738 }
739 
741 {
743  SyncStatus res;
744  res.state = m_state;
745  res.protocolVersion = 62;
747  res.currentBlockNumber = host().chain().number();
749  return res;
750 }
751 
753 {
754  m_downloadingHeaders.clear();
755  m_downloadingBodies.clear();
756  m_headers.clear();
757  m_bodies.clear();
758  m_headerSyncPeers.clear();
759  m_bodySyncPeers.clear();
760  m_headerIdToNumber.clear();
763 }
764 
766 {
768  resetSync();
769  m_highestBlock = 0;
770  m_haveCommonHeader = false;
771  host().bq().clear();
775 }
776 
778 {
779  resetSync();
781 }
782 
784 {
786 }
787 
789 {
790  return m_state != SyncState::Idle;
791 }
792 
793 void BlockChainSync::onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, std::vector<std::pair<h256, u256>> const& _hashes)
794 {
797  if (_peer->isConversing())
798  {
799  clog(NetMessageDetail) << "Ignoring new hashes since we're already downloading.";
800  return;
801  }
802  clog(NetMessageDetail) << "Not syncing and new block hash discovered: syncing.";
803  unsigned knowns = 0;
804  unsigned unknowns = 0;
805  unsigned maxHeight = 0;
806  for (auto const& p: _hashes)
807  {
808  h256 const& h = p.first;
809  _peer->addRating(1);
810  DEV_GUARDED(_peer->x_knownBlocks)
811  _peer->m_knownBlocks.insert(h);
812  auto status = host().bq().blockStatus(h);
813  if (status == QueueStatus::Importing || status == QueueStatus::Ready || host().chain().isKnown(h))
814  knowns++;
815  else if (status == QueueStatus::Bad)
816  {
817  cwarn << "block hash bad!" << h << ". Bailing...";
818  return;
819  }
820  else if (status == QueueStatus::Unknown)
821  {
822  unknowns++;
823  if (p.second > maxHeight)
824  {
825  maxHeight = (unsigned)p.second;
826  _peer->m_latestHash = h;
827  }
828  }
829  else
830  knowns++;
831  }
832  clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns";
833  if (unknowns > 0)
834  {
835  clog(NetMessageDetail) << "Not syncing and new block hash discovered: syncing.";
836  syncPeer(_peer, true);
837  }
838 }
839 
841 {
843  // Can't check invariants here since the peers is already removed from the list and the state is not updated yet.
845  continueSync();
847 }
848 
850 {
851  if (!isSyncing() && !m_headers.empty())
852  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Got headers while not syncing"));
853  if (!isSyncing() && !m_bodies.empty())
854  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Got bodies while not syncing"));
856  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Common block not found"));
857  if (isSyncing() && !m_headers.empty() && m_lastImportedBlock >= m_headers.begin()->first)
858  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Header is too old"));
859  if (m_headerSyncPeers.empty() != m_downloadingHeaders.empty())
860  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Header download map mismatch"));
861  if (m_bodySyncPeers.empty() != m_downloadingBodies.empty() && m_downloadingBodies.size() <= m_headerIdToNumber.size())
862  BOOST_THROW_EXCEPTION(FailedInvariant() << errinfo_comment("Body download map mismatch"));
863  return true;
864 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
unsigned startBlockNumber
Definition: CommonNet.h:105
void restartSync()
Restart sync.
h256Hash m_knownNewHashes
New hashes we know about use for logging only.
h256 EmptyListSHA3
Definition: SHA3.cpp:36
u256 const & number() const
Definition: BlockHeader.h:162
BlockDetails details(h256 const &_hash) const
Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
Definition: BlockChain.h:156
void onPeerNewHashes(std::shared_ptr< EthereumPeer > _peer, std::vector< std::pair< h256, u256 >> const &_hashes)
void onPeerBlockHeaders(std::shared_ptr< EthereumPeer > _peer, RLP const &_r)
Called by peer once it has new block headers during sync.
bool invariants() const override
Reimplement to specify the invariants.
bool m_haveCommonHeader
True if common block for our and remote chain has been found.
unsigned m_startingBlock
Last block number for the start of sync.
Handler m_bqRoomAvailable
Triggered once block queue has space for more blocks.
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
h256 hash(IncludeSeal _i=WithSeal) const
Definition: BlockHeader.cpp:64
bytesConstRef data() const
The bare data of the RLP.
Definition: RLP.h:97
size_t itemCount() const
Definition: RLP.h:118
void completeSync()
Called after all blocks have been downloaded Public only for test mode.
Encapsulation of a block header.
Definition: BlockHeader.h:95
Downloading blocks.
#define T(i, x)
void abortSync()
Abort all sync activity.
std::ostream & operator<<(std::ostream &_out, BlockHeader const &_bi)
Definition: BlockHeader.h:194
#define h(i)
Definition: sha.cpp:736
h256 const & transactionsRoot() const
Definition: BlockHeader.h:159
size_t count
Definition: ExecStats.cpp:37
h256 m_lastImportedBlockHash
Last imported block hash.
Handler onRoomAvailable(T const &_t)
Definition: BlockQueue.h:272
h256 const EmptyTrie
Definition: OverlayDB.cpp:33
unsigned m_lastImportedBlock
Last imported block number.
std::hash for asio::adress
Definition: Common.h:323
std::unordered_set< unsigned > m_downloadingHeaders
Set of block body numbers being downloaded.
assert(len-trim+(2 *lenIndices)<=WIDTH)
The EthereumHost class.
Definition: EthereumHost.h:61
u256 m_syncingTotalDifficulty
Highest peer difficulty.
h256 const & sha3Uncles() const
Definition: BlockHeader.h:155
unsigned protocolVersion
Definition: CommonNet.h:104
SyncState m_state
Current sync state.
QueueStatus blockStatus(h256 const &_h) const
Get some infomration on the given block&#39;s status regarding us.
Definition: BlockQueue.cpp:386
ExecStats::duration min
Definition: ExecStats.cpp:35
std::map< std::weak_ptr< EthereumPeer >, std::vector< unsigned >, std::owner_less< std::weak_ptr< EthereumPeer > > > m_headerSyncPeers
Peers to m_downloadingSubchain number map.
SyncStatus status() const
void clear()
Clear everything.
Definition: BlockQueue.cpp:74
#define DEV_INVARIANT_CHECK_HERE
Definition: Common.h:258
std::map< unsigned, std::vector< Header > > m_headers
Downloaded headers.
Initial chain sync complete. Waiting for new packets.
h256 const & parentHash() const
Definition: BlockHeader.h:154
void continueSync()
Resume downloading after witing state.
#define DEV_GUARDED(MUTEX)
Simple block guard.
Definition: Guards.h:144
Used to identify header by transactions and uncles hashes.
unsigned const c_maxRequestBodies
#define DEV_INVARIANT_CHECK
Scope guard for invariant check in a class derived from HasInvariants.
Definition: Common.h:257
static unsigned const c_oldProtocolVersion
Definition: EthereumHost.h:93
Initial chain sync has not started yet.
unsigned m_highestBlock
Highest block number seen.
void pauseSync()
Enter waiting state.
unsigned number(h256 const &_hash) const
Get a number for the given hash (or the most recent mined if none given). Thread-safe.
Definition: BlockChain.h:225
h256 numberHash(unsigned _i) const
Get the hash for a given block&#39;s number.
Definition: BlockChain.h:183
ExecStats::duration max
Definition: ExecStats.cpp:36
std::unordered_set< unsigned > m_downloadingBodies
Set of block header numbers being downloaded.
h256 currentHash() const
Get a given block (RLP format). Thread-safe.
Definition: BlockChain.h:229
std::vector< byte > bytes
Definition: Common.h:75
BlockChain const & chain() const
Definition: EthereumHost.h:85
std::vector< unsigned char > toBytes() const
Definition: vector_ref.h:45
const char * networkId
#define cwarn
Definition: Log.h:304
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
void foreachPeer(std::function< bool(std::shared_ptr< EthereumPeer >)> const &_f) const
bool isKnown(h256 const &_hash, bool _isCurrent=true) const
Returns true if the given block is known (though not necessarily a part of the canon chain)...
void onPeerAborting()
Called by peer when it is disconnecting.
void onPeerBlockBodies(std::shared_ptr< EthereumPeer > _peer, RLP const &_r)
Called by peer once it has new block bodies.
unsigned currentBlockNumber
Definition: CommonNet.h:106
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:78
void syncPeer(std::shared_ptr< EthereumPeer > _peer, bool _force)
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
h256 trieRootOver(unsigned _itemCount, T const &_getKey, U const &_getValue)
Definition: TrieHash.h:35
BlockQueue & bq()
Definition: EthereumHost.h:87
Block downloading paused. Waiting for block queue to process blocks and free space.
#define clog(X)
Definition: Log.h:295
std::lock_guard< std::recursive_mutex > RecursiveGuard
Definition: Guards.h:43
std::map< std::weak_ptr< EthereumPeer >, std::vector< unsigned >, std::owner_less< std::weak_ptr< EthereumPeer > > > m_bodySyncPeers
Peers to m_downloadingSubchain number map.
void onPeerStatus(std::shared_ptr< EthereumPeer > _peer)
Called by peer to report status.
u256 difficulty() const
Definition: BlockQueue.cpp:529
EthereumHost & host()
void swapOut(bytes &_dest)
Swap the contents of the output stream out for some other byte array.
Definition: RLP.h:439
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
Definition: Common.h:326
unsigned highestBlockNumber
Definition: CommonNet.h:107
std::vector< h256 > h256s
Definition: FixedHash.h:345
std::map< unsigned, std::vector< bytes > > m_bodies
Downloaded block bodies.
void logNewBlock(h256 const &_h)
_T toInt(int _flags=Strict) const
Converts to int of type given; if isString(), decodes as big-endian bytestream.
Definition: RLP.h:275
Class for writing to an RLP bytestream.
Definition: RLP.h:383
void onBlockImported(BlockHeader const &_info)
Called when a blockchain has imported a new block onto the DB.
RLPStream & appendRaw(bytesConstRef _rlp, size_t _itemCount=1)
Appends raw (pre-serialised) RLP data. Use with caution.
Definition: RLP.cpp:230
Downloading blocks learned from NewHashes packet.
uint8_t const * data
Definition: sha3.h:19
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
void onPeerNewBlock(std::shared_ptr< EthereumPeer > _peer, RLP const &_r)
Called by peer once it has new block bodies.
void requestBlocks(std::shared_ptr< EthereumPeer > _peer)
unsigned const c_maxPeerUknownNewBlocks
unsigned const c_maxRequestHeaders
Max number of unknown new blocks peer can give us.
std::unordered_map< HeaderId, unsigned, HeaderIdHash > m_headerIdToNumber
bytes RLPEmptyList
The empty list in RLP format.
Definition: RLP.cpp:27