41 unsigned const EthereumHost::c_oldProtocolVersion = 62;
42 static unsigned const c_maxSendTransactions = 256;
44 char const*
const EthereumHost::s_stateNames[
static_cast<int>(SyncState::Size)] = {
"NotSynced",
"Idle",
"Waiting",
"Blocks",
"State",
"NewBlocks" };
59 void onPeerStatus(std::shared_ptr<EthereumPeer> _peer)
override 64 m_sync.onPeerStatus(_peer);
66 catch (FailedInvariant
const&)
69 clog(NetWarn) <<
"Failed invariant during sync, restarting sync";
74 void onPeerTransactions(std::shared_ptr<EthereumPeer> _peer,
RLP const& _r)
override 78 m_tq.enqueue(_r, _peer->id());
81 void onPeerAborting()
override 86 m_sync.onPeerAborting();
90 cwarn <<
"Exception on peer destruciton: " << boost::current_exception_diagnostic_information();
94 void onPeerBlockHeaders(std::shared_ptr<EthereumPeer> _peer,
RLP const& _headers)
override 99 m_sync.onPeerBlockHeaders(_peer, _headers);
101 catch (FailedInvariant
const&)
104 clog(NetWarn) <<
"Failed invariant during sync, restarting sync";
105 m_sync.restartSync();
109 void onPeerBlockBodies(std::shared_ptr<EthereumPeer> _peer,
RLP const& _r)
override 114 m_sync.onPeerBlockBodies(_peer, _r);
116 catch (FailedInvariant
const&)
119 clog(NetWarn) <<
"Failed invariant during sync, restarting sync";
120 m_sync.restartSync();
124 void onPeerNewHashes(std::shared_ptr<EthereumPeer> _peer, std::vector<std::pair<h256, u256>>
const& _hashes)
override 129 m_sync.onPeerNewHashes(_peer, _hashes);
131 catch (FailedInvariant
const&)
134 clog(NetWarn) <<
"Failed invariant during sync, restarting sync";
135 m_sync.restartSync();
139 void onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer,
RLP const& _r)
override 144 m_sync.onPeerNewBlock(_peer, _r);
146 catch (FailedInvariant
const&)
149 clog(NetWarn) <<
"Failed invariant during sync, restarting sync";
150 m_sync.restartSync();
154 void onPeerNodeData(std::shared_ptr<EthereumPeer> ,
RLP const& _r)
override 160 void onPeerReceipts(std::shared_ptr<EthereumPeer> ,
RLP const& _r)
override 175 EthereumHostData(
BlockChain const& _chain,
OverlayDB const& _db): m_chain(_chain), m_db(_db) {}
177 pair<bytes, unsigned> blockHeaders(
RLP const& _blockId,
unsigned _maxHeaders,
u256 _skip,
bool _reverse)
const override 179 auto numHeadersToSend = _maxHeaders;
181 auto step =
static_cast<unsigned>(_skip) + 1;
182 assert(step > 0 &&
"step must not be 0");
185 if (_blockId.
size() == 32)
188 clog(NetMessageSummary) <<
"GetBlockHeaders (block (hash): " << blockHash
189 <<
", maxHeaders: " << _maxHeaders
190 <<
", skip: " << _skip <<
", reverse: " << _reverse <<
")";
192 if (!m_chain.isKnown(blockHash))
196 auto n = m_chain.number(blockHash);
197 if (numHeadersToSend == 0)
199 else if (n != 0 || blockHash == m_chain.genesisHash())
201 auto top = n + uint64_t(step) * numHeadersToSend - 1;
202 auto lastBlock = m_chain.number();
205 numHeadersToSend = (lastBlock - n) / step + 1;
206 top = n + step * (numHeadersToSend - 1);
208 assert(top <= lastBlock &&
"invalid top block calculated");
209 blockHash = m_chain.numberHash(static_cast<unsigned>(top));
218 clog(NetMessageSummary) <<
"GetBlockHeaders (" << n
219 <<
"max: " << _maxHeaders
220 <<
"skip: " << _skip << (_reverse ?
"reverse" :
"") <<
")";
224 auto lastBlock = m_chain.number();
225 if (n > lastBlock || numHeadersToSend == 0)
229 bigint top = n + uint64_t(step) * (numHeadersToSend - 1);
232 numHeadersToSend = (lastBlock -
static_cast<unsigned>(n)) / step + 1;
233 top = n + step * (numHeadersToSend - 1);
235 assert(top <= lastBlock &&
"invalid top block calculated");
236 blockHash = m_chain.numberHash(static_cast<unsigned>(top));
240 blockHash = m_chain.numberHash(static_cast<unsigned>(n));
245 auto nextHash = [
this](
h256 _h,
unsigned _step)
247 static const unsigned c_blockNumberUsageLimit = 1000;
249 const auto lastBlock = m_chain.number();
250 const auto limitBlock = lastBlock > c_blockNumberUsageLimit ? lastBlock - c_blockNumberUsageLimit : 0;
254 auto details = m_chain.details(_h);
255 if (details.number < limitBlock)
263 auto n = m_chain.number(_h);
265 _h = m_chain.numberHash(n - _step);
275 unsigned itemCount = 0;
277 for (
unsigned i = 0; i != numHeadersToSend; ++i)
279 if (!blockHash || !m_chain.isKnown(blockHash))
282 hashes.push_back(blockHash);
285 blockHash = nextHash(blockHash, step);
288 for (
unsigned i = 0; i < hashes.size() && rlp.size() < c_maxPayload; ++i)
289 rlp += m_chain.headerData(hashes[_reverse ? i : hashes.size() - 1 - i]);
291 return make_pair(rlp, itemCount);
294 pair<bytes, unsigned> blockBodies(
RLP const& _blockHashes)
const override 296 unsigned const count =
static_cast<unsigned>(_blockHashes.
itemCount());
300 auto numBodiesToSend =
std::min(count, c_maxBlocks);
301 for (
unsigned i = 0; i < numBodiesToSend && rlp.size() < c_maxPayload; ++i)
304 if (m_chain.isKnown(
h))
306 bytes blockBytes = m_chain.block(
h);
307 RLP block{blockBytes};
312 auto bodyBytes = body.
out();
313 rlp.insert(rlp.end(), bodyBytes.begin(), bodyBytes.end());
317 if (count > 20 && n == 0)
318 clog(NetWarn) <<
"all" << count <<
"unknown blocks requested; peer on different chain?";
320 clog(NetMessageSummary) << n <<
"blocks known and returned;" << (numBodiesToSend - n) <<
"blocks unknown;" << (count > c_maxBlocks ? count - c_maxBlocks : 0) <<
"blocks ignored";
322 return make_pair(rlp, n);
325 strings nodeData(
RLP const& _dataHashes)
const override 327 unsigned const count =
static_cast<unsigned>(_dataHashes.
itemCount());
330 size_t payloadSize = 0;
331 auto numItemsToSend =
std::min(count, c_maxNodes);
332 for (
unsigned i = 0; i < numItemsToSend && payloadSize < c_maxPayload; ++i)
335 auto node = m_db.lookup(
h);
338 payloadSize += node.length();
339 data.push_back(move(node));
342 clog(NetMessageSummary) << data.size() <<
" nodes known and returned;" << (numItemsToSend - data.size()) <<
" unknown;" << (count > c_maxNodes ? count - c_maxNodes : 0) <<
" ignored";
347 pair<bytes, unsigned> receipts(
RLP const& _blockHashes)
const override 349 unsigned const count =
static_cast<unsigned>(_blockHashes.
itemCount());
353 auto numItemsToSend =
std::min(count, c_maxReceipts);
354 for (
unsigned i = 0; i < numItemsToSend && rlp.size() < c_maxPayload; ++i)
357 if (m_chain.isKnown(
h))
359 auto const receipts = m_chain.receipts(
h);
360 auto receiptsRlpList = receipts.rlp();
361 rlp.insert(rlp.end(), receiptsRlpList.begin(), receiptsRlpList.end());
365 clog(NetMessageSummary) << n <<
" receipt lists known and returned;" << (numItemsToSend - n) <<
" unknown;" << (count > c_maxReceipts ? count - c_maxReceipts : 0) <<
" ignored";
367 return make_pair(rlp, n);
384 m_networkId (_networkId),
385 m_hostData(make_shared<EthereumHostData>(m_chain, m_db))
449 time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
453 foreachPeer([](std::shared_ptr<EthereumPeer> _p) { _p->tick();
return true; });
464 unordered_map<std::shared_ptr<EthereumPeer>, std::vector<size_t>> peerTransactions;
468 for (
size_t i = 0; i < ts.size(); ++i)
470 auto const& t = ts[i];
473 for (
auto const& p: peers)
474 peerTransactions[p].push_back(i);
476 for (
auto const& t: ts)
483 for (
auto const& i: peerTransactions[_p])
485 _p->m_knownTransactions.insert(ts[i].
sha3());
490 _p->clearKnownTransactions();
492 if (n || _p->m_requireTransactions)
499 _p->m_requireTransactions =
false;
508 auto sessionLess = [](std::pair<std::shared_ptr<SessionFace>, std::shared_ptr<Peer>>
const& _left, std::pair<std::shared_ptr<SessionFace>, std::shared_ptr<Peer>>
const& _right)
509 {
return _left.first->rating() == _right.first->rating() ? _left.first->connectionTime() < _right.first->connectionTime() : _left.first->rating() > _right.first->rating(); };
511 std::sort(sessions.begin(), sessions.end(), sessionLess);
512 for (
auto s: sessions)
513 if (!_f(capabilityFromSession<EthereumPeer>(*s.first)))
517 std::sort(sessions.begin(), sessions.end(), sessionLess);
518 for (
auto s: sessions)
525 vector<shared_ptr<EthereumPeer>> chosen;
526 vector<shared_ptr<EthereumPeer>> allowed;
527 vector<shared_ptr<SessionFace>> sessions;
529 size_t peerCount = 0;
532 if (_allow(_p.get()))
534 allowed.push_back(_p);
535 sessions.push_back(_p->session());
541 size_t chosenSize = (peerCount * _percent + 99) / 100;
542 chosen.reserve(chosenSize);
543 for (
unsigned i = chosenSize; i && allowed.size(); i--)
545 unsigned n = rand() % allowed.size();
546 chosen.push_back(std::move(allowed[n]));
547 allowed.erase(allowed.begin() + n);
549 return make_tuple(move(chosen), move(allowed), move(sessions));
557 if (detailsFrom.totalDifficulty < detailsTo.totalDifficulty)
559 if (
diff(detailsFrom.number, detailsTo.number) < 20)
571 for (shared_ptr<EthereumPeer>
const& p: get<0>(s))
572 for (
auto const&
b: blocks)
581 for (shared_ptr<EthereumPeer>
const& p: get<1>(s))
585 for (
auto const&
b: blocks)
603 return m_sync->isSyncing();
618 std::shared_ptr<EthereumPeer> peer = capabilityFromSession<EthereumPeer>(*session);
624 Guard l(peer->x_knownTransactions);
625 peer->m_knownTransactions.insert(_h);
629 peer->addRating(-100);
638 peer->addRating(100);
648 auto cap = capabilityFromSession<EthereumPeer>(*_s, _cap.second);
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
SyncStatus status() const
#define function(a, b, c, d, k, s)
std::atomic< time_t > m_lastTick
std::tuple< h256s, h256, unsigned > treeRoute(h256 const &_from, h256 const &_to, bool _common=true, bool _pre=true, bool _post=true) const
BlockDetails details(h256 const &_hash) const
Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
A queue of Transactions, each stored as RLP.
std::vector< std::pair< std::shared_ptr< SessionFace >, std::shared_ptr< Peer > > > peerSessions() const
Handler< ImportResult, h256 const &, h512 const & > onImport(T const &_t)
Register a handler that will be called once asynchronous verification is comeplte an transaction has ...
virtual ~EthereumHost()
Will block on network process events.
virtual std::shared_ptr< Capability > newPeerCapability(std::shared_ptr< SessionFace > const &_s, unsigned _idOffset, CapDesc const &_cap, uint16_t _capID)
std::tuple< std::vector< std::shared_ptr< EthereumPeer > >, std::vector< std::shared_ptr< EthereumPeer > >, std::vector< std::shared_ptr< p2p::SessionFace > > > randomSelection(unsigned _percent=25, std::function< bool(EthereumPeer *)> const &_allow=[](EthereumPeer const *){return true;})
Implements the blockchain database.
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
std::pair< std::string, u256 > CapDesc
void maintainBlocks(h256 const &_currentBlock)
RLPStream & append(unsigned _s)
Append given datum to the byte stream.
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<>> bigint
bytes const & out() const
Read the byte stream.
std::vector< std::string > strings
std::hash for asio::adress
assert(len-trim+(2 *lenIndices)<=WIDTH)
unsigned protocolVersion() const
void onTransactionImported(ImportResult _ir, h256 const &_h, h512 const &_nodeId)
h256Hash m_transactionsSent
std::unique_ptr< BlockChainSync > m_sync
void maintainTransactions()
std::recursive_mutex RecursiveMutex
Transactions topTransactions(unsigned _limit, h256Hash const &_avoid=h256Hash()) const
Get top transactions from the queue.
#define DEV_GUARDED(MUTEX)
Simple block guard.
virtual void doWork() override
Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from...
h256Hash m_knownBlocks
Blocks that the peer already knows about (that don't need to be sent to them).
_N toHash(int _flags=Strict) const
Base class for all exceptions.
static unsigned const c_oldProtocolVersion
bool ensureInitialised()
Initialises the network peer-state, doing the stuff that needs to be once-only.
std::lock_guard< std::mutex > Guard
std::shared_ptr< EthereumHostDataFace > m_hostData
unsigned number(h256 const &_hash) const
Get a number for the given hash (or the most recent mined if none given). Thread-safe.
void completeSync()
Don't sync further - used only in test mode.
BlockChain const & m_chain
h256 currentHash() const
Get a given block (RLP format). Thread-safe.
std::vector< byte > bytes
RLPStream & appendList(size_t _items)
Appends a list.
std::shared_ptr< EthereumPeerObserverFace > m_peerObserver
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
TransactionQueue & m_tq
Maintains a list of incoming transactions not yet in a block on the blockchain.
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)...
RLPStream & prep(RLPStream &_s, unsigned _id, unsigned _args=0)
Base BlockChain synchronization strategy class.
void sealAndSend(RLPStream &_s)
bool m_requireTransactions
Have we received a GetTransactions packet that we haven't yet answered?
N diff(N const &_a, N const &_b)
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
std::shared_ptr< p2p::Capability > newPeerCapability(std::shared_ptr< p2p::SessionFace > const &_s, unsigned _idOffset, p2p::CapDesc const &_cap, uint16_t _capID) override
h256Hash m_knownTransactions
Transactions that the peer already knows of.
std::lock_guard< std::recursive_mutex > RecursiveGuard
h256 genesisHash() const
Get the hash of the genesis block. Thread-safe.
bytes block(h256 const &_hash) const
Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe.
std::vector< h256 > h256s
_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.
RLPStream & appendRaw(bytesConstRef _rlp, size_t _itemCount=1)
Appends raw (pre-serialised) RLP data. Use with caution.
h256Hash knownTransactions() const
Get a hash set of transactions in the queue.
Class for interpreting Recursive Linear-Prefix Data.
std::shared_ptr< SessionFace > peerSession(NodeID const &_id)
Get session by id.