48 _out <<
"state: " << EthereumHost::stateName(_sync.
state) <<
" ";
49 if (_sync.
state == SyncState::Blocks || _sync.
state == SyncState::NewBlocks)
57 template<
typename T>
bool haveItem(std::map<unsigned, T>& _container,
unsigned _number)
59 if (_container.empty())
61 auto lower = _container.lower_bound(_number);
62 if (lower != _container.end() && lower->first == _number)
64 if (lower == _container.begin())
67 return lower->first <= _number && (lower->first + lower->second.size()) > _number;
70 template<
typename T>
T const* findItem(std::map<
unsigned, std::vector<T>>& _container,
unsigned _number)
72 if (_container.empty())
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())
80 if (lower->first <= _number && (lower->first + lower->second.size()) > _number)
81 return &lower->second.at(_number - lower->first);
85 template<
typename T>
void removeItem(std::map<
unsigned, std::vector<T>>& _container,
unsigned _number)
87 if (_container.empty())
89 auto lower = _container.lower_bound(_number);
90 if (lower != _container.end() && lower->first == _number)
92 _container.erase(lower);
95 if (lower == _container.begin())
98 if (lower->first <= _number && (lower->first + lower->second.size()) > _number)
99 lower->second.erase(lower->second.begin() + (_number - lower->first), lower->second.end());
102 template<
typename T>
void removeAllStartingWith(std::map<
unsigned, std::vector<T>>& _container,
unsigned _number)
104 if (_container.empty())
106 auto lower = _container.lower_bound(_number);
107 if (lower != _container.end() && lower->first == _number)
109 _container.erase(lower, _container.end());
112 if (lower == _container.begin())
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());
123 template<
typename T>
void mergeInto(std::map<
unsigned, std::vector<T>>& _container,
unsigned _number,
T&& _data)
125 assert(!haveItem(_container, _number));
126 auto lower = _container.lower_bound(_number);
127 if (!_container.empty() && lower != _container.begin())
129 if (lower != _container.end() && (lower->first + lower->second.size() == _number))
132 lower->second.emplace_back(_data);
136 if (next != _container.end() && (lower->first + lower->second.size() == next->first))
139 std::move(next->second.begin(), next->second.end(), std::back_inserter(lower->second));
140 _container.erase(next);
147 auto inserted = _container.insert(lower, std::make_pair(_number, std::vector<T> { _data }));
148 auto next = inserted;
150 if (next != _container.end() && next->first == _number + 1)
152 std::move(next->second.begin(), next->second.end(), std::back_inserter(inserted->second));
153 _container.erase(next);
162 m_startingBlock(_host.chain().number()),
163 m_lastImportedBlock(m_startingBlock),
164 m_lastImportedBlockHash(_host.chain().currentHash())
207 std::shared_ptr<SessionFace> session = _peer->session();
210 if (_peer->m_genesisHash !=
host().chain().genesisHash())
211 _peer->disable(
"Invalid genesis hash");
213 _peer->disable(
"Invalid protocol version.");
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.");
221 _peer->disable(
"Peer banned for unexpected status message.");
230 clog(NetAllDetail) <<
"Can't sync with this peer - outstanding asks.";
238 if (
host().bq().isActive())
243 if (_force || _peer->m_totalDifficulty > syncingDifficulty)
249 _peer->requestBlockHeaders(_peer->m_latestHash, 1, 0,
false);
250 _peer->m_requireTransactions =
true;
273 if (
host().bq().knownFull())
275 clog(NetAllDetail) <<
"Waiting for block queue before downloading blocks";
282 vector<unsigned> neededNumbers;
288 unsigned block = header->first + index;
291 neededBodies.push_back(header->second[index].hash);
292 neededNumbers.push_back(block);
297 if (index >= header->second.size())
301 if (neededBodies.size() > 0)
304 _peer->requestBlockBodies(neededBodies);
333 while (count == 0 && next !=
m_headers.end())
341 std::vector<unsigned> headers;
342 for (
unsigned block = start; block < start +
count; block++)
345 headers.push_back(block);
348 count = headers.size();
353 _peer->requestBlockHeaders(start, count, 0,
false);
355 else if (start >= next->first)
357 start = next->first + next->second.size();
363 _peer->requestBlockHeaders(start, 1, 0,
false);
372 for (
unsigned block :
syncPeer->second)
379 for (
unsigned block :
syncPeer->second)
389 if (s->first.expired())
391 for (
unsigned block : s->second)
400 if (s->first.expired())
402 for (
unsigned block : s->second)
414 clog(NetNote) <<
"NewBlock: " << _h;
423 clog(NetMessageSummary) <<
"BlocksHeaders (" << dec << itemCount <<
"entries)" << (itemCount ?
"" :
": NoMoreHeaders");
427 clog(NetMessageSummary) <<
"Ignoring unexpected blocks";
432 clog(NetAllDetail) <<
"Ignored blocks while waiting";
437 clog(NetAllDetail) <<
"Peer does not have the blocks requested";
438 _peer->addRating(-1);
440 for (
unsigned i = 0; i < itemCount; i++)
443 unsigned blockNumber =
static_cast<unsigned>(info.
number());
446 clog(NetMessageSummary) <<
"Skipping header " << blockNumber;
451 clog(NetMessageSummary) <<
"Skipping header " << blockNumber;
476 clog(NetImpolite) <<
"Unknown block header " << blockNumber <<
" " << info.
hash() <<
" (Restart syncing)";
477 _peer->addRating(-1);
483 if (nextBlock && nextBlock->
parent != info.
hash())
485 clog(NetImpolite) <<
"Unknown block header " << blockNumber + 1 <<
" " << nextBlock->
hash;
487 unsigned n = blockNumber + 1;
489 for (
auto const&
h : headers)
497 removeAllStartingWith(
m_headers, blockNumber + 1);
498 removeAllStartingWith(
m_bodies, blockNumber + 1);
502 mergeInto(
m_headers, blockNumber, std::move(hdr));
511 mergeInto(
m_bodies, blockNumber, std::move(body));
526 clog(NetMessageSummary) <<
"BlocksBodies (" << dec << itemCount <<
"entries)" << (itemCount ?
"" :
": NoMoreBodies");
529 clog(NetMessageSummary) <<
"Ignoring unexpected blocks";
534 clog(NetAllDetail) <<
"Ignored blocks while waiting";
539 clog(NetAllDetail) <<
"Peer does not have the blocks requested";
540 _peer->addRating(-1);
542 for (
unsigned i = 0; i < itemCount; i++)
546 auto txList = body[0];
547 h256 transactionRoot =
trieRootOver(txList.itemCount(), [&](
unsigned i){
return rlp(i); }, [&](
unsigned i){
return txList[i].data().toBytes(); });
549 HeaderId id { transactionRoot, uncles };
553 clog(NetAllDetail) <<
"Ignored unknown block body";
556 unsigned blockNumber = iter->second;
557 if (haveItem(
m_bodies, blockNumber))
559 clog(NetMessageSummary) <<
"Skipping already downloaded block body " << blockNumber;
580 unsigned success = 0;
583 unsigned unknown = 0;
585 for (; i < headers.second.size() && i < bodies.second.size(); i++)
588 blockStream.
appendRaw(headers.second[i].data);
589 RLP body(bodies.second[i]);
594 switch (
host().bq().
import(&block))
628 clog(NetMessageSummary) << dec << success <<
"imported OK," << unknown <<
"with unknown parents," << future <<
"with future timestamps," << got <<
" already known received.";
630 if (
host().bq().unknownFull())
632 clog(NetWarn) <<
"Too many unknown blocks, restarting sync";
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;
645 if (!newHeaders.empty())
647 if (!newBodies.empty())
648 m_bodies[newBodiesHead] = newBodies;
665 _peer->disable(
"NewBlock without 2 data fields.");
669 auto h = info.
hash();
671 _peer->m_knownBlocks.insert(
h);
672 unsigned blockNumber =
static_cast<unsigned>(info.
number());
675 clog(NetAllDetail) <<
"Received unknown new block";
679 switch (
host().bq().
import(_r[0].
data()))
682 _peer->addRating(100);
698 clog(NetMessageDetail) <<
"Block headers map is empty, but block bodies map is not. Force-clearing.";
711 _peer->disable(
"Malformed block received.");
721 _peer->m_unknownNewBlocks++;
724 _peer->disable(
"Too many uknown new blocks");
729 if (totalDifficulty > _peer->m_totalDifficulty)
731 clog(NetMessageDetail) <<
"Received block with no known parent. Peer needs syncing...";
797 if (_peer->isConversing())
799 clog(NetMessageDetail) <<
"Ignoring new hashes since we're already downloading.";
802 clog(NetMessageDetail) <<
"Not syncing and new block hash discovered: syncing.";
804 unsigned unknowns = 0;
805 unsigned maxHeight = 0;
806 for (
auto const& p: _hashes)
808 h256 const&
h = p.first;
811 _peer->m_knownBlocks.insert(h);
817 cwarn <<
"block hash bad!" << h <<
". Bailing...";
823 if (p.second > maxHeight)
825 maxHeight = (unsigned)p.second;
826 _peer->m_latestHash = h;
832 clog(NetMessageSummary) << knowns <<
"knowns," << unknowns <<
"unknowns";
835 clog(NetMessageDetail) <<
"Not syncing and new block hash discovered: syncing.";
852 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Got headers while not syncing"));
854 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Got bodies while not syncing"));
856 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Common block not found"));
858 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Header is too old"));
860 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Header download map mismatch"));
862 BOOST_THROW_EXCEPTION(FailedInvariant() <<
errinfo_comment(
"Body download map mismatch"));
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
unsigned startBlockNumber
void restartSync()
Restart sync.
h256Hash m_knownNewHashes
New hashes we know about use for logging only.
BlockDetails details(h256 const &_hash) const
Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
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.
bytesConstRef data() const
The bare data of the RLP.
void completeSync()
Called after all blocks have been downloaded Public only for test mode.
void abortSync()
Abort all sync activity.
std::ostream & operator<<(std::ostream &_out, BlockHeader const &_bi)
h256 m_lastImportedBlockHash
Last imported block hash.
Handler onRoomAvailable(T const &_t)
unsigned m_lastImportedBlock
Last imported block number.
std::hash for asio::adress
std::unordered_set< unsigned > m_downloadingHeaders
Set of block body numbers being downloaded.
assert(len-trim+(2 *lenIndices)<=WIDTH)
u256 m_syncingTotalDifficulty
Highest peer difficulty.
SyncState m_state
Current sync state.
QueueStatus blockStatus(h256 const &_h) const
Get some infomration on the given block's status regarding us.
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.
#define DEV_INVARIANT_CHECK_HERE
std::map< unsigned, std::vector< Header > > m_headers
Downloaded headers.
Initial chain sync complete. Waiting for new packets.
void continueSync()
Resume downloading after witing state.
#define DEV_GUARDED(MUTEX)
Simple block guard.
unsigned const c_maxRequestBodies
#define DEV_INVARIANT_CHECK
Scope guard for invariant check in a class derived from HasInvariants.
static unsigned const c_oldProtocolVersion
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.
h256 numberHash(unsigned _i) const
Get the hash for a given block's number.
std::unordered_set< unsigned > m_downloadingBodies
Set of block header numbers being downloaded.
h256 currentHash() const
Get a given block (RLP format). Thread-safe.
std::vector< byte > bytes
BlockChain const & chain() const
std::vector< unsigned char > toBytes() const
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
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
boost::error_info< struct tag_comment, std::string > errinfo_comment
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.
h256 trieRootOver(unsigned _itemCount, T const &_getKey, U const &_getValue)
Block downloading paused. Waiting for block queue to process blocks and free space.
std::lock_guard< std::recursive_mutex > RecursiveGuard
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.
void swapOut(bytes &_dest)
Swap the contents of the output stream out for some other byte array.
dev::WithExisting max(dev::WithExisting _a, dev::WithExisting _b)
unsigned highestBlockNumber
std::vector< h256 > h256s
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.
Class for writing to an RLP bytestream.
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.
Downloading blocks learned from NewHashes packet.
Class for interpreting Recursive Linear-Prefix Data.
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.