/*
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>
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>()
enum class ImportResult
{
Success = 0 ,
UnknownParent ,
FutureTime ,
AlreadyInChain ,
AlreadyKnown ,
Malformed
} ;
/**
* @ 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 ) ;
/// 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 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 ) ;
/// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them.
void doneDrain ( ) { WriteGuard l ( m_lock ) ; m_drainingSet . clear ( ) ; }
/// 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 ) ; }
/// 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 ( ) ; }
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.
} ;
}
}