Gav Wood
11 years ago
12 changed files with 478 additions and 214 deletions
@ -0,0 +1,102 @@ |
|||
/*
|
|||
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.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "BlockQueue.h" |
|||
|
|||
#include <libethential/Log.h> |
|||
#include <libethcore/Exceptions.h> |
|||
#include <libethcore/BlockInfo.h> |
|||
#include "BlockChain.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
bool BlockQueue::import(bytesConstRef _block, BlockChain const& _bc) |
|||
{ |
|||
// Check if we already know this block.
|
|||
h256 h = sha3(_block); |
|||
|
|||
UpgradableGuard l(m_lock); |
|||
if (m_readySet.count(h) || m_futureSet.count(h)) |
|||
// Already know about this one.
|
|||
return false; |
|||
|
|||
// VERIFY: populates from the block and checks the block is internally coherent.
|
|||
BlockInfo bi; |
|||
|
|||
#if ETH_CATCH |
|||
try |
|||
#endif |
|||
{ |
|||
bi.populate(_block); |
|||
bi.verifyInternals(_block); |
|||
} |
|||
#if ETH_CATCH |
|||
catch (Exception const& _e) |
|||
{ |
|||
cwarn << "Ignoring malformed block: " << _e.description(); |
|||
return false; |
|||
} |
|||
#endif |
|||
auto newHash = eth::sha3(_block); |
|||
|
|||
// Check block doesn't already exist first!
|
|||
if (_bc.details(newHash)) |
|||
return false; |
|||
|
|||
// Check it's not crazy
|
|||
if (bi.timestamp > (u256)time(0)) |
|||
return false; |
|||
|
|||
UpgradeGuard ul(l); |
|||
|
|||
// We now know it.
|
|||
if (!m_readySet.count(bi.parentHash) && !_bc.details(bi.parentHash)) |
|||
{ |
|||
// We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on.
|
|||
m_future.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); |
|||
m_futureSet.insert(h); |
|||
return true; |
|||
} |
|||
|
|||
// If valid, append to blocks.
|
|||
m_ready.push_back(_block.toBytes()); |
|||
m_readySet.insert(h); |
|||
|
|||
noteReadyWithoutWriteGuard(h); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void BlockQueue::noteReadyWithoutWriteGuard(h256 _b) |
|||
{ |
|||
auto r = m_future.equal_range(_b); |
|||
h256s good; |
|||
for (auto it = r.first; it != r.second; ++it) |
|||
{ |
|||
m_futureSet.erase(it->second.first); |
|||
m_ready.push_back(it->second.second); |
|||
m_readySet.erase(it->second.first); |
|||
good.push_back(it->second.first); |
|||
} |
|||
m_future.erase(r.first, r.second); |
|||
for (auto g: good) |
|||
noteReadyWithoutWriteGuard(g); |
|||
} |
@ -0,0 +1,66 @@ |
|||
/*
|
|||
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 <libethential/Common.h> |
|||
#include "libethcore/CommonEth.h" |
|||
#include "Guards.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
class BlockChain; |
|||
|
|||
/**
|
|||
* @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.
|
|||
bool import(bytesConstRef _tx, BlockChain const& _bc); |
|||
|
|||
/// Grabs the blocks that are ready, giving them in the correct order for insertion into the chain.
|
|||
void drain(std::vector<bytes>& o_out) { WriteGuard l(m_lock); swap(o_out, m_ready); m_readySet.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_future.size()); } |
|||
|
|||
private: |
|||
void noteReadyWithoutWriteGuard(h256 _b); |
|||
|
|||
mutable boost::shared_mutex m_lock; ///< General lock.
|
|||
std::set<h256> m_readySet; ///< All blocks ready for chain-import.
|
|||
std::vector<bytes> m_ready; ///< List of blocks, in correct order, ready for chain-import.
|
|||
std::set<h256> m_futureSet; ///< Set of all blocks whose parents are not ready/in-chain.
|
|||
std::multimap<h256, std::pair<h256, bytes>> m_future; ///< For transactions that have an unknown parent; we map their parent hash to the block stuff, and insert once the block appears.
|
|||
}; |
|||
|
|||
} |
|||
|
|||
|
Loading…
Reference in new issue