25 #include <libp2p/Host.h> 26 #include <libp2p/Session.h> 34 static unsigned const c_maxSendTransactions = 256;
35 static unsigned const c_maxHeadersToSend = 1024;
36 static unsigned const c_maxIncomingNewHashes = 1024;
37 static int const c_backroundWorkPeriodMs = 1000;
38 static int const c_minBlockBroadcastPeers = 4;
40 char const*
const EthereumCapability::s_stateNames[
static_cast<int>(SyncState::Size)] = {
41 "NotSynced",
"Idle",
"Waiting",
"Blocks",
"State"};
49 case Asking::BlockHeaders:
50 return "BlockHeaders";
51 case Asking::BlockBodies:
53 case Asking::NodeData:
55 case Asking::Receipts:
61 case Asking::WarpManifest:
62 return "WarpManifest";
63 case Asking::WarpData:
72 EthereumPeerObserver(shared_ptr<BlockChainSync> _sync,
TransactionQueue& _tq): m_sync(_sync), m_tq(_tq) {}
78 m_sync->onPeerStatus(_peer);
80 catch (FailedInvariant
const&)
83 cwarn <<
"Failed invariant during sync, restarting sync";
84 m_sync->restartSync();
88 void onPeerTransactions(
NodeID const& _peerID,
RLP const& _r)
override 91 LOG(m_logger) <<
"Transactions (" << dec << itemCount <<
" entries)";
92 m_tq.enqueue(_r, _peerID);
95 void onPeerAborting()
override 99 m_sync->onPeerAborting();
103 cwarn <<
"Exception on peer destruciton: " << boost::current_exception_diagnostic_information();
107 void onPeerBlockHeaders(
NodeID const& _peerID,
RLP const& _headers)
override 111 m_sync->onPeerBlockHeaders(_peerID, _headers);
113 catch (FailedInvariant
const&)
116 cwarn <<
"Failed invariant during sync, restarting sync";
117 m_sync->restartSync();
121 void onPeerBlockBodies(
NodeID const& _peerID,
RLP const& _r)
override 125 m_sync->onPeerBlockBodies(_peerID, _r);
127 catch (FailedInvariant
const&)
130 cwarn <<
"Failed invariant during sync, restarting sync";
131 m_sync->restartSync();
135 void onPeerNewHashes(
136 NodeID const& _peerID, std::vector<std::pair<h256, u256>>
const& _hashes)
override 140 m_sync->onPeerNewHashes(_peerID, _hashes);
142 catch (FailedInvariant
const&)
145 cwarn <<
"Failed invariant during sync, restarting sync";
146 m_sync->restartSync();
150 void onPeerNewBlock(
NodeID const& _peerID,
RLP const& _r)
override 154 m_sync->onPeerNewBlock(_peerID, _r);
156 catch (FailedInvariant
const&)
159 cwarn <<
"Failed invariant during sync, restarting sync";
160 m_sync->restartSync();
164 void onPeerNodeData(
NodeID const& ,
RLP const& _r)
override 167 LOG(m_logger) <<
"Node Data (" << dec << itemCount <<
" entries)";
170 void onPeerReceipts(
NodeID const& ,
RLP const& _r)
override 173 LOG(m_logger) <<
"Receipts (" << dec << itemCount <<
" entries)";
177 shared_ptr<BlockChainSync> m_sync;
186 EthereumHostData(
BlockChain const& _chain,
OverlayDB const& _db): m_chain(_chain), m_db(_db) {}
188 pair<bytes, unsigned> blockHeaders(
RLP const& _blockId,
unsigned _maxHeaders,
u256 _skip,
bool _reverse)
const override 190 auto numHeadersToSend = _maxHeaders;
192 auto step =
static_cast<unsigned>(_skip) + 1;
193 assert(step > 0 &&
"step must not be 0");
196 if (_blockId.
size() == 32)
199 cnetlog <<
"GetBlockHeaders (block (hash): " << blockHash
200 <<
", maxHeaders: " << _maxHeaders <<
", skip: " << _skip
201 <<
", reverse: " << _reverse <<
")";
203 if (!m_chain.isKnown(blockHash))
207 auto n = m_chain.number(blockHash);
208 if (numHeadersToSend == 0)
210 else if (n != 0 || blockHash == m_chain.genesisHash())
212 auto top = n + uint64_t(step) * numHeadersToSend - 1;
213 auto lastBlock = m_chain.number();
216 numHeadersToSend = (lastBlock - n) / step + 1;
217 top = n + step * (numHeadersToSend - 1);
219 assert(top <= lastBlock &&
"invalid top block calculated");
220 blockHash = m_chain.numberHash(static_cast<unsigned>(top));
229 cnetlog <<
"GetBlockHeaders (" << n <<
" max: " << _maxHeaders <<
" skip: " << _skip
230 << (_reverse ?
" reverse" :
"") <<
")";
234 auto lastBlock = m_chain.number();
235 if (n > lastBlock || numHeadersToSend == 0)
239 bigint top = n + uint64_t(step) * (numHeadersToSend - 1);
242 numHeadersToSend = (lastBlock -
static_cast<unsigned>(n)) / step + 1;
243 top = n + step * (numHeadersToSend - 1);
245 assert(top <= lastBlock &&
"invalid top block calculated");
246 blockHash = m_chain.numberHash(static_cast<unsigned>(top));
249 else if (n <= std::numeric_limits<unsigned>::max())
250 blockHash = m_chain.numberHash(static_cast<unsigned>(n));
255 auto nextHash = [
this](
h256 _h,
unsigned _step)
257 static const unsigned c_blockNumberUsageLimit = 1000;
259 const auto lastBlock = m_chain.number();
260 const auto limitBlock = lastBlock > c_blockNumberUsageLimit ? lastBlock - c_blockNumberUsageLimit : 0;
264 auto details = m_chain.details(_h);
265 if (details.number < limitBlock)
273 auto n = m_chain.number(_h);
275 _h = m_chain.numberHash(n - _step);
285 unsigned itemCount = 0;
287 for (
unsigned i = 0; i != numHeadersToSend; ++i)
289 if (!blockHash || !m_chain.isKnown(blockHash))
292 hashes.push_back(blockHash);
295 blockHash = nextHash(blockHash, step);
298 for (
unsigned i = 0; i < hashes.size() &&
rlp.size() < c_maxPayload; ++i)
299 rlp += m_chain.headerData(hashes[_reverse ? i : hashes.size() - 1 - i]);
301 return make_pair(
rlp, itemCount);
304 pair<bytes, unsigned> blockBodies(
RLP const& _blockHashes)
const override 306 unsigned const count =
static_cast<unsigned>(_blockHashes.
itemCount());
310 auto numBodiesToSend = std::min(count, c_maxBlocks);
311 for (
unsigned i = 0; i < numBodiesToSend &&
rlp.size() < c_maxPayload; ++i)
314 if (m_chain.isKnown(h))
316 bytes blockBytes = m_chain.block(h);
317 RLP block{blockBytes};
322 auto bodyBytes = body.
out();
323 rlp.insert(
rlp.end(), bodyBytes.begin(), bodyBytes.end());
327 if (count > 20 && n == 0)
328 cnetlog <<
"all " << count <<
" unknown blocks requested; peer on different chain?";
330 cnetlog << n <<
" blocks known and returned; " << (numBodiesToSend - n)
331 <<
" blocks unknown; " << (count > c_maxBlocks ? count - c_maxBlocks : 0)
332 <<
" blocks ignored";
334 return make_pair(
rlp, n);
337 strings nodeData(
RLP const& _dataHashes)
const override 339 unsigned const count =
static_cast<unsigned>(_dataHashes.
itemCount());
342 size_t payloadSize = 0;
343 auto numItemsToSend = std::min(count, c_maxNodes);
344 for (
unsigned i = 0; i < numItemsToSend && payloadSize < c_maxPayload; ++i)
347 auto node = m_db.lookup(h);
350 payloadSize += node.length();
351 data.push_back(move(node));
354 cnetlog << data.
size() <<
" nodes known and returned; " << (numItemsToSend - data.size())
355 <<
" unknown; " << (count > c_maxNodes ? count - c_maxNodes : 0) <<
" ignored";
360 pair<bytes, unsigned> receipts(
RLP const& _blockHashes)
const override 362 unsigned const count =
static_cast<unsigned>(_blockHashes.
itemCount());
366 auto numItemsToSend = std::min(count, c_maxReceipts);
367 for (
unsigned i = 0; i < numItemsToSend &&
rlp.size() < c_maxPayload; ++i)
370 if (m_chain.isKnown(h))
372 auto const receipts = m_chain.receipts(h);
373 auto receiptsRlpList = receipts.rlp();
374 rlp.insert(
rlp.end(), receiptsRlpList.begin(), receiptsRlpList.end());
378 cnetlog << n <<
" receipt lists known and returned; " << (numItemsToSend - n)
379 <<
" unknown; " << (count > c_maxReceipts ? count - c_maxReceipts : 0)
382 return make_pair(
rlp, n);
392 EthereumCapability::EthereumCapability(shared_ptr<p2p::CapabilityHostFace> _host,
395 : m_host(move(_host)),
400 m_networkId(_networkId),
401 m_hostData(new EthereumHostData(m_chain, m_db))
406 m_peerObserver.reset(
new EthereumPeerObserver(m_sync, m_tq));
409 std::random_device seed;
410 m_urng = std::mt19937_64(seed());
415 m_backgroundWorkEnabled =
true;
416 m_host->scheduleExecution(c_backroundWorkPeriodMs, [
this]() { doBackgroundWork(); });
421 m_backgroundWorkEnabled =
false;
424 bool EthereumCapability::ensureInitialised()
426 if (!m_latestBlockSent)
430 LOG(m_logger) <<
"Initialising: latest=" << m_latestBlockSent;
444 m_host->scheduleExecution(0, [
this]() {
445 m_latestBlockSent =
h256();
446 m_transactionsSent.clear();
452 m_sync->completeSync();
455 void EthereumCapability::doBackgroundWork()
462 if (m_newTransactions)
464 m_newTransactions =
false;
465 maintainTransactions();
474 time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
475 if (now - m_lastTick >= 1)
478 for (
auto const&
peer : m_peers)
480 time_t now = std::chrono::system_clock::to_time_t(chrono::system_clock::now());
484 m_host->disconnect(
peer.first, p2p::PingTimeout);
488 if (m_backgroundWorkEnabled)
489 m_host->scheduleExecution(c_backroundWorkPeriodMs, [
this]() { doBackgroundWork(); });
492 void EthereumCapability::maintainTransactions()
495 unordered_map<NodeID, std::vector<size_t>> peerTransactions;
498 for (
size_t i = 0; i < ts.size(); ++i)
500 auto const& t = ts[i];
501 bool unsent = !m_transactionsSent.count(t.sha3());
502 auto const peers = selectPeers([&](
EthereumPeer const& _peer) {
506 for (
auto const& p: peers)
507 peerTransactions[p].push_back(i);
509 for (
auto const& t: ts)
510 m_transactionsSent.insert(t.sha3());
513 for (
auto&
peer : m_peers)
517 for (
auto const& i : peerTransactions[
peer.first])
528 m_host->sealAndSend(
peer.first, ts);
529 LOG(m_logger) <<
"Sent " << n <<
" transactions to " <<
peer.first;
535 vector<NodeID> EthereumCapability::selectPeers(
536 std::function<
bool(
EthereumPeer const&)>
const& _predicate)
const 538 vector<NodeID> allowed;
539 for (
auto const&
peer : m_peers)
541 if (_predicate(
peer.second))
542 allowed.push_back(
peer.first);
547 std::pair<std::vector<NodeID>, std::vector<NodeID>> EthereumCapability::randomPartitionPeers(
548 std::vector<NodeID>
const& _peers, std::size_t _number)
const 550 vector<NodeID> part1(_peers);
551 vector<NodeID> part2;
553 if (_number >= _peers.size())
554 return std::make_pair(part1, part2);
556 std::shuffle(part1.begin(), part1.end(), m_urng);
559 std::move(part1.begin() + _number, part1.end(), std::back_inserter(part2));
560 part1.erase(part1.begin() + _number, part1.end());
561 return std::make_pair(move(part1), move(part2));
564 void EthereumCapability::maintainBlocks(
h256 const& _currentHash)
567 auto detailsFrom = m_chain.
details(m_latestBlockSent);
568 auto detailsTo = m_chain.
details(_currentHash);
569 if (detailsFrom.totalDifficulty < detailsTo.totalDifficulty)
571 if (
diff(detailsFrom.number, detailsTo.number) < 20)
574 LOG(m_logger) <<
"Sending new blocks (current is " << _currentHash <<
", was " 575 << m_latestBlockSent <<
")";
577 h256s blocks = get<0>(m_chain.
treeRoute(m_latestBlockSent, _currentHash,
false,
false,
true));
580 auto const peersWithoutBlock = selectPeers(
583 auto const peersToSendNumber =
584 std::max<std::size_t>(c_minBlockBroadcastPeers, std::sqrt(m_peers.size()));
586 std::vector<NodeID> peersToSend;
587 std::vector<NodeID> peersToAnnounce;
588 std::tie(peersToSend, peersToAnnounce) =
589 randomPartitionPeers(peersWithoutBlock, peersToSendNumber);
591 for (
NodeID const& peerID : peersToSend)
592 for (
auto const& b: blocks)
596 .appendRaw(m_chain.
block(b), 1)
599 auto itPeer = m_peers.find(peerID);
600 if (itPeer != m_peers.end())
602 m_host->sealAndSend(peerID, ts);
603 itPeer->second.clearKnownBlocks();
606 if (!peersToSend.empty())
607 LOG(m_logger) <<
"Sent " << blocks.size() <<
" block(s) to " << peersToSend.size()
610 for (
NodeID const& peerID : peersToAnnounce)
614 for (
auto const& b: blocks)
621 auto itPeer = m_peers.find(peerID);
622 if (itPeer != m_peers.end())
624 m_host->sealAndSend(peerID, ts);
625 itPeer->second.clearKnownBlocks();
628 if (!peersToAnnounce.empty())
629 LOG(m_logger) <<
"Announced " << blocks.size() <<
" block(s) to " 630 << peersToAnnounce.size() <<
" peers";
632 m_latestBlockSent = _currentHash;
638 return m_sync->isSyncing();
643 return m_sync->status();
646 void EthereumCapability::onTransactionImported(
649 m_host->scheduleExecution(0, [
this, _ir, _h, _nodeId]() {
650 auto itPeerStatus = m_peers.find(_nodeId);
651 if (itPeerStatus == m_peers.end())
654 auto&
peer = itPeerStatus->second;
660 m_host->updateRating(_nodeId, -100);
664 m_transactionsSent.insert(_h);
665 m_host->updateRating(_nodeId, 0);
668 m_host->updateRating(_nodeId, 100);
677 m_host->addNote(_peerID,
"manners", m_host->isRude(_peerID,
name()) ?
"RUDE" :
"nice");
680 m_peers.emplace(_peerID,
peer);
688 m_peerObserver->onPeerAborting();
690 m_peers.erase(_peerID);
694 NodeID const& _peerID,
unsigned _id,
RLP const& _r)
696 auto&
peer = m_peers[_peerID];
697 peer.
setLastAsk(std::chrono::system_clock::to_time_t(chrono::system_clock::now()));
705 auto const peerProtocolVersion = _r[0].
toInt<
unsigned>();
707 auto const totalDifficulty = _r[2].
toInt<
u256>();
709 auto const genesisHash = _r[4].
toHash<
h256>();
711 LOG(m_logger) <<
"Status: " << peerProtocolVersion <<
" / " <<
networkId <<
" / " 712 << genesisHash <<
", TD: " << totalDifficulty <<
" = " << latestHash;
715 peerProtocolVersion,
networkId, totalDifficulty, latestHash, genesisHash);
717 m_peerObserver->onPeerStatus(
peer);
722 m_peerObserver->onPeerTransactions(_peerID, _r);
729 const auto blockId = _r[0];
730 const auto maxHeaders = _r[1].
toInt<
u256>();
732 const auto reverse = _r[3].
toInt<
bool>();
734 auto numHeadersToSend = maxHeaders <= c_maxHeadersToSend ?
735 static_cast<unsigned>(maxHeaders) :
738 if (skip > std::numeric_limits<unsigned>::max() - 1)
740 cnetdetails <<
"Requested block skip is too big: " << skip;
744 pair<bytes, unsigned>
const rlpAndItemCount =
745 m_hostData->blockHeaders(blockId, numHeadersToSend, skip, reverse);
749 .appendRaw(rlpAndItemCount.first, rlpAndItemCount.second);
750 m_host->sealAndSend(_peerID, s);
751 m_host->updateRating(_peerID, 0);
757 LOG(m_loggerImpolite)
758 <<
"Peer giving us block headers when we didn't ask for them.";
762 m_peerObserver->onPeerBlockHeaders(_peerID, _r);
768 unsigned count =
static_cast<unsigned>(_r.
itemCount());
769 cnetlog <<
"GetBlockBodies (" << dec << count <<
" entries)";
773 LOG(m_loggerImpolite) <<
"Zero-entry GetBlockBodies: Not replying.";
774 m_host->updateRating(_peerID, -10);
778 pair<bytes, unsigned>
const rlpAndItemCount = m_hostData->blockBodies(_r);
780 m_host->updateRating(_peerID, 0);
783 .appendRaw(rlpAndItemCount.first, rlpAndItemCount.second);
784 m_host->sealAndSend(_peerID, s);
790 LOG(m_loggerImpolite) <<
"Peer giving us block bodies when we didn't ask for them.";
794 m_peerObserver->onPeerBlockBodies(_peerID, _r);
800 m_peerObserver->onPeerNewBlock(_peerID, _r);
807 cnetlog <<
"BlockHashes (" << dec << itemCount <<
" entries) " 808 << (itemCount ?
"" :
" : NoMoreHashes");
810 if (itemCount > c_maxIncomingNewHashes)
816 vector<pair<h256, u256>> hashes(itemCount);
817 for (
unsigned i = 0; i < itemCount; ++i)
818 hashes[i] = std::make_pair(_r[i][0].toHash<h256>(), _r[i][1].toInt<u256>());
820 m_peerObserver->onPeerNewHashes(_peerID, hashes);
825 unsigned count =
static_cast<unsigned>(_r.
itemCount());
828 LOG(m_loggerImpolite) <<
"Zero-entry GetNodeData: Not replying.";
829 m_host->updateRating(_peerID, -10);
832 cnetlog <<
"GetNodeData (" << dec << count <<
" entries)";
834 strings const data = m_hostData->nodeData(_r);
836 m_host->updateRating(_peerID, 0);
839 for (
auto const& element : data)
841 m_host->sealAndSend(_peerID, s);
846 unsigned count =
static_cast<unsigned>(_r.
itemCount());
849 LOG(m_loggerImpolite) <<
"Zero-entry GetReceipts: Not replying.";
850 m_host->updateRating(_peerID, -10);
853 cnetlog <<
"GetReceipts (" << dec << count <<
" entries)";
855 pair<bytes, unsigned>
const rlpAndItemCount = m_hostData->receipts(_r);
857 m_host->updateRating(_peerID, 0);
860 .appendRaw(rlpAndItemCount.first, rlpAndItemCount.second);
861 m_host->sealAndSend(_peerID, s);
867 LOG(m_loggerImpolite) <<
"Peer giving us node data when we didn't ask for them.";
871 m_peerObserver->onPeerNodeData(_peerID, _r);
878 LOG(m_loggerImpolite) <<
"Peer giving us receipts when we didn't ask for them.";
882 m_peerObserver->onPeerReceipts(_peerID, _r);
892 cnetlog <<
"Peer causing an Exception: " 893 << boost::current_exception_diagnostic_information() <<
" " << _r;
895 catch (std::exception
const& _e)
897 cnetlog <<
"Peer causing an exception: " << _e.what() <<
" " << _r;
903 void EthereumCapability::setIdle(
NodeID const& _peerID)
908 void EthereumCapability::setAsking(
NodeID const& _peerID,
Asking _a)
910 auto itPeerStatus = m_peers.find(_peerID);
911 if (itPeerStatus == m_peers.end())
914 auto& peerStatus = itPeerStatus->second;
916 peerStatus.setAsking(_a);
917 peerStatus.setLastAsk(std::chrono::system_clock::to_time_t(chrono::system_clock::now()));
919 m_host->addNote(_peerID,
"ask", ::
toString(_a));
920 m_host->addNote(_peerID,
"sync",
921 string(isCriticalSyncing(_peerID) ?
"ONGOING" :
"holding") +
922 (needsSyncing(_peerID) ?
" & needed" :
""));
925 bool EthereumCapability::isCriticalSyncing(
NodeID const& _peerID)
const 927 auto itPeerStatus = m_peers.find(_peerID);
928 if (itPeerStatus == m_peers.end())
931 auto const& peerStatus = itPeerStatus->second;
933 auto const asking = peerStatus.asking();
937 bool EthereumCapability::needsSyncing(
NodeID const& _peerID)
const 939 if (m_host->isRude(_peerID,
name()))
942 auto peerStatus = m_peers.find(_peerID);
943 return (peerStatus != m_peers.end() && peerStatus->second.latestHash());
948 m_host->disableCapability(_peerID,
name(), _problem);
958 auto peer = m_peers.find(_peerID);
959 if (
peer == m_peers.end())
960 BOOST_THROW_EXCEPTION(PeerDisconnected() <<
errinfo_nodeID(_peerID));
void requestStatus(u256 _hostNetworkId, u256 _chainTotalDifficulty, h256 _chainCurrentHash, h256 _chainGenesPeersh)
_T toInt(int _flags=Strict) const
Converts to int of type given; if isData(), decodes as big-endian bytestream.
void setWaitingForTransactions(bool _value)
void onStopping() override
A queue of Transactions, each stored as RLP. Maintains a transaction queue sorted by nonce diff and g...
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 ...
void onDisconnect(NodeID const &_nodeID) override
bool isWaitingForTransactions() const
Implements the blockchain database. All data this gives is disk-backed. .
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
BlockDetails details(h256 const &_hash) const
Get the familial details concerning a block (or the most recent mined if none given). Thread-safe.
void setLastAsk(time_t _lastAsk)
RLPStream & append(unsigned _s)
Append given datum to the byte stream.
void completeSync()
Don't sync further - used only in test mode.
bool interpretCapabilityPacket(NodeID const &_peerID, unsigned _id, RLP const &_r) override
void setStatus(unsigned _protocolVersion, u256 const &_networkId, u256 const &_totalDifficulty, h256 const &_latestHash, h256 const &_genesisHash)
void markTransactionAsKnown(h256 const &_hash)
The EthereumCapability class.
std::vector< std::string > strings
unsigned number(h256 const &_hash) const
Get a number for the given hash (or the most recent mined if none given). Thread-safe.
void onStarting() override
EthereumPeer const & peer(NodeID const &_peerID) const
bool isBlockKnown(h256 const &_hash) const
std::string toString(std::chrono::time_point< T > const &_e, std::string const &_format="%F %T")
void disablePeer(NodeID const &_peerID, std::string const &_problem)
bool isConversing() const
bool sha3(bytesConstRef _input, bytesRef o_output) noexcept
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<> > bigint
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)...
Base class for all exceptions.
std::tuple< h256s, h256, unsigned > treeRoute(h256 const &_from, h256 const &_to, bool _common=true, bool _pre=true, bool _post=true) const
Logger createLogger(int _severity, std::string const &_channel)
std::vector< byte > bytes
RLPStream & appendList(size_t _items)
Appends a list.
void onConnect(NodeID const &_nodeID, u256 const &_peerCapabilityVersion) override
A queue of blocks. Sits between network or other I/O and the BlockChain. Sorts them ready for blockch...
h256 genesisHash() const
Get the hash of the genesis block. Thread-safe.
h256Hash knownTransactions() const
boost::error_info< struct tag_nodeID, h512 > errinfo_nodeID
h256 currentHash() const
Get a given block (RLP format). Thread-safe.
bytes const & out() const
Read the byte stream.
Base BlockChain synchronization strategy class. Syncs to peers and keeps up to date. Base class handles blocks downloading but does not contain any details on state transfer logic.
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void > > u256
SyncStatus status() const
N diff(N const &_a, N const &_b)
std::string name() const override
Transactions topTransactions(unsigned _limit, h256Hash const &_avoid=h256Hash()) const
std::vector< h256 > h256s
Class for writing to an RLP bytestream.
_N toHash(int _flags=Strict) const
RLPStream & appendRaw(bytesConstRef _rlp, size_t _itemCount=1)
Appends raw (pre-serialised) RLP data. Use with caution.
bool isTransactionKnown(h256 const &_hash) const
boost::log::sources::severity_channel_logger<> Logger
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.