You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
4.6 KiB
110 lines
4.6 KiB
/*
|
|
This file is part of cpp-ethereum.
|
|
|
|
cpp-ethereum is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
cpp-ethereum is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/** @file BlockQueue.h
|
|
* @author Gav Wood <i@gavwood.com>
|
|
* @date 2014
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <boost/thread.hpp>
|
|
#include <libdevcore/Common.h>
|
|
#include <libdevcore/Log.h>
|
|
#include <libethcore/Common.h>
|
|
#include <libdevcore/Guards.h>
|
|
#include <libethcore/Common.h>
|
|
|
|
namespace dev
|
|
{
|
|
namespace eth
|
|
{
|
|
|
|
class BlockChain;
|
|
|
|
struct BlockQueueChannel: public LogChannel { static const char* name() { return "[]Q"; } static const int verbosity = 4; };
|
|
#define cblockq dev::LogOutputStream<dev::eth::BlockQueueChannel, true>()
|
|
|
|
struct BlockQueueStatus
|
|
{
|
|
size_t ready;
|
|
size_t future;
|
|
size_t unknown;
|
|
size_t bad;
|
|
};
|
|
|
|
/**
|
|
* @brief A queue of blocks. Sits between network or other I/O and the BlockChain.
|
|
* Sorts them ready for blockchain insertion (with the BlockChain::sync() method).
|
|
* @threadsafe
|
|
*/
|
|
class BlockQueue
|
|
{
|
|
public:
|
|
/// Import a block into the queue.
|
|
ImportResult import(bytesConstRef _tx, BlockChain const& _bc, bool _isOurs = false);
|
|
|
|
/// Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
|
|
void tick(BlockChain const& _bc);
|
|
|
|
/// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain.
|
|
/// Don't forget to call doneDrain() once you're done importing.
|
|
void drain(std::vector<bytes>& o_out, unsigned _max);
|
|
|
|
/// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them.
|
|
/// @returns true iff there are additional blocks ready to be processed.
|
|
bool doneDrain(h256s const& _knownBad = h256s());
|
|
|
|
/// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain).
|
|
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); }
|
|
|
|
/// Force a retry of all the blocks with unknown parents.
|
|
void retryAllUnknown();
|
|
|
|
/// Get information on the items queued.
|
|
std::pair<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
|
|
|
|
/// Clear everything.
|
|
void clear() { WriteGuard l(m_lock); m_readySet.clear(); m_drainingSet.clear(); m_ready.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); }
|
|
|
|
/// Return first block with an unknown parent.
|
|
h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); }
|
|
|
|
/// Get some infomration on the current status.
|
|
BlockQueueStatus status() const { ReadGuard l(m_lock); return BlockQueueStatus{m_ready.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; }
|
|
|
|
/// Get some infomration on the given block's status regarding us.
|
|
ImportResult blockStatus(h256 const& _h) const { ReadGuard l(m_lock); return m_readySet.count(_h) || m_drainingSet.count(_h) ? ImportResult::AlreadyKnown : m_unknownSet.count(_h) ? ImportResult::UnknownParent : m_knownBad.count(_h) ? ImportResult::BadChain : ImportResult::Unknown; }
|
|
|
|
template <class T> Handler onReady(T const& _t) { return m_onReady.add(_t); }
|
|
|
|
private:
|
|
void noteReadyWithoutWriteGuard(h256 _b);
|
|
void notePresentWithoutWriteGuard(bytesConstRef _block);
|
|
|
|
mutable boost::shared_mutex m_lock; ///< General lock.
|
|
std::set<h256> m_readySet; ///< All blocks ready for chain-import.
|
|
std::set<h256> m_drainingSet; ///< All blocks being imported.
|
|
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import.
|
|
std::set<h256> m_unknownSet; ///< Set of all blocks whose parents are not ready/in-chain.
|
|
std::multimap<h256, std::pair<h256, bytes>> m_unknown; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
|
|
std::multimap<unsigned, bytes> m_future; ///< Set of blocks that are not yet valid.
|
|
std::set<h256> m_knownBad; ///< Set of blocks that we know will never be valid.
|
|
Signal m_onReady; ///< Called when a subsequent call to import transactions will return a non-empty container. Be nice and exit fast.
|
|
};
|
|
|
|
}
|
|
}
|
|
|