From 87bb1195a5b1caf1386b12471d5853a086c09c1d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 12 Apr 2015 12:15:17 +0200 Subject: [PATCH] Half-finished Miner/Farm framework. --- libdevcore/Worker.cpp | 16 ++-- libdevcore/Worker.h | 6 +- libethcore/Miner.cpp | 12 +++ libethcore/Miner.h | 146 +++++++++++++++++++++++++++++ libethcore/ProofOfWork.cpp | 56 ++++++----- libethcore/ProofOfWork.h | 126 ++++++++----------------- libethereum/Client.cpp | 2 +- libethereum/Client.h | 4 +- libethereum/Farm.cpp | 12 +++ libethereum/Farm.h | 153 +++++++++++++++++++++++++++++++ libethereum/Miner.cpp | 2 +- libethereum/Miner.h | 97 +------------------- libethereum/TransactionQueue.cpp | 5 +- libethereum/TransactionQueue.h | 14 ++- libethereumx/Ethereum.h | 2 +- 15 files changed, 432 insertions(+), 221 deletions(-) create mode 100644 libethcore/Miner.cpp create mode 100644 libethcore/Miner.h create mode 100644 libethereum/Farm.cpp create mode 100644 libethereum/Farm.h diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index 175323620..bc8fe97f2 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -39,12 +39,7 @@ void Worker::startWorking() { setThreadName(m_name.c_str()); startedWorking(); - while (!m_stop) - { - if (m_idleWaitMs) - this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); - doWork(); - } + workLoop(); cnote << "Finishing up worker thread"; doneWorking(); })); @@ -63,3 +58,12 @@ void Worker::stopWorking() cnote << "Stopped" << m_name; } +void Worker::workLoop() +{ + while (!m_stop) + { + if (m_idleWaitMs) + this_thread::sleep_for(chrono::milliseconds(m_idleWaitMs)); + doWork(); + } +} diff --git a/libdevcore/Worker.h b/libdevcore/Worker.h index 40bc118aa..6a35d6c4c 100644 --- a/libdevcore/Worker.h +++ b/libdevcore/Worker.h @@ -57,7 +57,11 @@ protected: virtual void startedWorking() {} /// Called continuously following sleep for m_idleWaitMs. - virtual void doWork() = 0; + virtual void doWork() {} + + /// Overrides doWork(); should call shouldStop() often and exit when true. + virtual void workLoop(); + bool shouldStop() const { return m_stop; } /// Called when is to be stopped, just prior to thread being joined. virtual void doneWorking() {} diff --git a/libethcore/Miner.cpp b/libethcore/Miner.cpp new file mode 100644 index 000000000..d6f15866f --- /dev/null +++ b/libethcore/Miner.cpp @@ -0,0 +1,12 @@ +#include "Miner.h" + +Miner::Miner() +{ + +} + +Miner::~Miner() +{ + +} + diff --git a/libethcore/Miner.h b/libethcore/Miner.h new file mode 100644 index 000000000..a7f17e565 --- /dev/null +++ b/libethcore/Miner.h @@ -0,0 +1,146 @@ +/* + 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 . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "State.h" + +namespace dev +{ + +namespace eth +{ + +struct WorkPackage +{ + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; +}; + +static const WorkPackage NullWorkPackage; + +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ + void combine(MiningProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } + double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. + double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. + double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. + unsigned hashes = 0; ///< Total number of hashes computed. + unsigned ms = 0; ///< Total number of milliseconds of mining thus far. +}; + +/** + * @brief Class for hosting one or more Miners. + * @warning Must be implemented in a threadsafe manner since it will be called from multiple + * miner threads. + */ +class FarmFace +{ +public: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; +}; + +/** + * @brief A miner - a member and adoptee of the Farm. + */ +class Miner +{ +public: + using ConstructionInfo = std::pair; + + Miner(ConstructionInfo const& _ci): + m_farm(_ci.first), + m_index(_ci.second) + {} + + // API FOR THE FARM TO CALL IN WITH + + void setWork(WorkPackage const& _work = WorkPackage()) + { + Guard l(x_work); + if (_work.headerHash != h256()) + kickOff(m_work); + else if (m_work.headerHash == h256() && _work.headerHash != h256()) + pause(); + m_work = _work; + } + + unsigned index() const { return m_index; } + +protected: + + // REQUIRED TO BE REIMPLEMENTED BY A SUBCLASS: + + /** + * @brief Begin working on a given work package, discarding any previous work. + * @param _work The package for which to find a solution. + */ + virtual void kickOff(WorkPackage const& _work) = 0; + + /** + * @brief No work left to be done. Pause until told to kickOff(). + */ + virtual void pause() = 0; + + // AVAILABLE FOR A SUBCLASS TO CALL: + + /** + * @brief Notes that the Miner found a solution. + * @param _s The solution. + * @return true if the solution was correct and that the miner should pause. + */ + bool submitProof(ProofOfWork::Solution const& _s) + { + if (m_farm) + { + Guard l(x_work); + return m_farm->submitProof(_s, m_work, this); + } + return true; + } + +private: + FarmFace* m_farm = nullptr; + unsigned m_index; + + Mutex x_work; + WorkPackage m_work; +}; + +} +} diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ffa787e3e..1b3b55f4d 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -45,13 +45,38 @@ namespace dev namespace eth { -bool EthashPoW::verify(BlockInfo const& _header) +void Ethash::CPUMiner::workLoop() { - return Ethasher::verify(_header); -} + Solution solution; + + class Miner + { + public: + Miner(BlockInfo const& _header): + m_headerHash(_header.headerHash(WithoutNonce)), + m_params(Ethasher::params(_header)), + m_datasetPointer(Ethasher::get()->full(_header).data()) + {} + + inline h256 mine(uint64_t _nonce) + { + ethash_compute_full(&m_ethashReturn, m_datasetPointer, &m_params, m_headerHash.data(), _nonce); +// cdebug << "Ethasher::mine hh:" << m_headerHash << "nonce:" << (Nonce)(u64)_nonce << " => " << h256(m_ethashReturn.result, h256::ConstructFromPointer); + return h256(m_ethashReturn.result, h256::ConstructFromPointer); + } + + inline h256 lastMixHash() const + { + return h256(m_ethashReturn.mix_hash, h256::ConstructFromPointer); + } + + private: + ethash_return_value m_ethashReturn; + h256 m_headerHash; + ethash_params m_params; + void const* m_datasetPointer; + }; -std::pair EthashCPU::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ Ethasher::Miner m(_header); std::pair ret; @@ -70,34 +95,21 @@ std::pair EthashCPU::mine(BlockInfo const& _heade double best = 1e99; // high enough to be effectively infinity :) Solution result; unsigned hashCount = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) + for (; !shouldStop(); tryNonce++, hashCount++) { h256 val(m.mine(tryNonce)); best = std::min(best, log2((double)(u256)val)); if (val <= boundary) { - ret.first.completed = true; - assert(Ethasher::eval(_header, (Nonce)(u64)tryNonce).value == val); - result.mixHash = m.lastMixHash(); - result.nonce = u64(tryNonce); - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - break; + if (submitProof(solution)) + return; } } ret.first.hashes = hashCount; ret.first.best = best; ret.second = result; - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(result, test); - assert(verify(test)); - } - - return ret; + return; } #if ETH_ETHASHCL || !ETH_TRUE diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index bd8ab58db..3ea177a9a 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "BlockInfo.h" +#include "Miner.h" #define FAKE_DAGGER 1 @@ -51,39 +52,56 @@ struct MineInfo bool completed = false; }; -class EthashPoW +class EthashCLHook; + +class Ethash { -public: - struct Solution - { - Nonce nonce; - h256 mixHash; - }; - static bool verify(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } +public: - virtual unsigned defaultTimeout() const { return 100; } - virtual std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) = 0; +struct Solution +{ + Nonce nonce; + h256 mixHash; }; -class EthashCPU: public EthashPoW +static bool verify(BlockInfo const& _header); +static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } + +class CPUMiner: public Miner, Worker { public: - std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; + CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} -protected: - Nonce m_last; + static unsigned instances() { return thread::hardware_concurrency(); } + + void kickOff(WorkPackage const& _work) override + { + stopWorking(); + m_work = _work; + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + + WorkPackage m_work; + MineInfo m_info; }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashCLHook; -class EthashCL: public EthashPoW +class GPUMiner: public NewMiner { public: - EthashCL(); - ~EthashCL(); + GPUMiner(ConstructionInfo const& _ci): NewMiner(_ci) + { + + } + + static unsigned instances() { return 1; } std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true) override; unsigned defaultTimeout() const override { return 500; } @@ -96,81 +114,15 @@ protected: std::unique_ptr m_hook; }; -using Ethash = EthashCL; #else -using Ethash = EthashCPU; -#endif -template -class ProofOfWorkEngine: public Evaluator -{ -public: - using Solution = Nonce; +using GPUMiner = CPUMiner; - static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r; } - unsigned defaultTimeout() const { return 100; } - -protected: - Nonce m_last; -}; +#endif -class SHA3Evaluator -{ -public: - static h256 eval(h256 const& _root, Nonce const& _nonce) { h256 b[2] = { _root, h256(_nonce) }; return sha3(bytesConstRef((byte const*)&b[0], 64)); } }; -using SHA3ProofOfWork = ProofOfWorkEngine; - using ProofOfWork = Ethash; -template -std::pair::Solution> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue) -{ - auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); - auto difficulty = _header.difficulty; - - std::pair ret; - static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); - Nonce::Arith s = (m_last = Nonce::random(s_eng)); - - bigint d = (bigint(1) << 256) / difficulty; - ret.first.requirement = log2((double)d); - - // 2^ 0 32 64 128 256 - // [--------*-------------------------] - // - // evaluate until we run out of time - auto startTime = std::chrono::steady_clock::now(); - double best = 1e99; // high enough to be effectively infinity :) - ProofOfWorkEngine::Solution solution; - unsigned h = 0; - for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++) - { - solution = (ProofOfWorkEngine::Solution)s; - auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); - best = std::min(best, log2((double)e)); - if (e <= d) - { - ret.first.completed = true; - break; - } - } - ret.first.hashes = h; - ret.first.best = best; - ret.second = solution; - - if (ret.first.completed) - { - BlockInfo test = _header; - assignResult(solution, test); - assert(verify(test)); - } - - return ret; -} - } } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 223384c3a..278c02fa8 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -467,7 +467,7 @@ void Client::doWork() cworkin << "WORK"; h256Set changeds; - auto maintainMiner = [&](Miner& m) + auto maintainMiner = [&](OldMiner& m) { if (m.isComplete()) { diff --git a/libethereum/Client.h b/libethereum/Client.h index ec852afd2..9af501f74 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -72,7 +72,7 @@ private: std::string m_path; }; -class RemoteMiner: public Miner +class RemoteMiner: public OldMiner { public: RemoteMiner() {} @@ -124,7 +124,7 @@ struct ClientDetail: public LogChannel { static const char* name() { return " C */ class Client: public MinerHost, public ClientBase, Worker { - friend class Miner; + friend class OldMiner; public: /// New-style Constructor. diff --git a/libethereum/Farm.cpp b/libethereum/Farm.cpp new file mode 100644 index 000000000..639e4efcf --- /dev/null +++ b/libethereum/Farm.cpp @@ -0,0 +1,12 @@ +#include "Farm.h" + +Farm::Farm() +{ + +} + +Farm::~Farm() +{ + +} + diff --git a/libethereum/Farm.h b/libethereum/Farm.h new file mode 100644 index 000000000..a49038f0d --- /dev/null +++ b/libethereum/Farm.h @@ -0,0 +1,153 @@ +/* + 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 . + */ +/** @file Miner.h + * @author Alex Leverington + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Miner.h" + +namespace dev +{ + +namespace eth +{ + +/** + * @brief A collective of Miners. + * Miners ask for work, then submit proofs + * @threadsafe + */ +template +class Farm: public FarmFace +{ +public: + /** + * @brief Sets the current mining mission. + * @param _bi The block (header) we wish to be mining. + */ + void setWork(BlockInfo const& _bi) + { + WriteGuard l(x_work); + m_header = _bi; + m_work.boundary = _bi.boundary(); + m_work.headerHash = _bi.headerHash(WithNonce); + m_work.seedHash = _bi.seedHash(); + ReadGuard l(x_miners); + for (auto const& m: miners) + m->setWork(m_work); + } + + /** + * @brief (Re)start miners for CPU only. + * @returns true if started properly. + */ + bool startCPU() { return start(); } + + /** + * @brief (Re)start miners for GPU only. + * @returns true if started properly. + */ + bool startGPU() { start(); } + + /** + * @brief Stop all mining activities. + */ + void stop() + { + WriteGuard l(x_miners); + m_miners.clear(); + } + + /** + * @brief Get information on the progress of mining this work package. + * @return The progress with mining so far. + */ + MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } + +protected: + // TO BE REIMPLEMENTED BY THE SUBCLASS + /** + * @brief Provides a valid header based upon that received previously with setWork(). + * @param _bi The now-valid header. + * @return true if the header was good and that the Farm should pause until more work is submitted. + */ + virtual bool submitHeader(BlockInfo const& _bi) = 0; + +private: + /** + * @brief Called from a Miner to note a WorkPackage has a solution. + * @param _p The solution. + * @param _wp The WorkPackage that the Solution is for. + * @return true iff the solution was good (implying that mining should be . + */ + bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp, NewMiner* _m) override + { + if (_wp.headerHash != m_work.headerHash) + return false; + + ProofOfWork::assignResult(_p, m_header); + if (submitHeader(m_header)) + { + ReadGuard l(x_miners); + for (std::shared_ptr const& m: m_miners) + if (m.get() != _m) + m->pause(); + m_work.headerHash = h256(); + return true; + } + return false; + } + + /** + * @brief Start a number of miners. + */ + template + bool start() + { + WriteGuard l(x_miners); + if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) + return true; + m_miners.clear(); + m_miners.reserve(MinerType::instances()); + for (unsigned i = 0; i < MinerType::instances(); ++i) + m_miners.push_back(new MinerType(std::make_pair(this, i))); + return true; + } + + mutable SharedMutex x_miners; + std::vector> m_miners; + + mutable SharedMutex x_progress; + MineProgress m_progress; + + mutable SharedMutex x_work; + WorkPackage m_work; + BlockInfo m_header; +}; + +} +} diff --git a/libethereum/Miner.cpp b/libethereum/Miner.cpp index dc3d9bd9e..b386fe868 100644 --- a/libethereum/Miner.cpp +++ b/libethereum/Miner.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -Miner::~Miner() {} +OldMiner::~OldMiner() {} LocalMiner::LocalMiner(MinerHost* _host, unsigned _id) { diff --git a/libethereum/Miner.h b/libethereum/Miner.h index 86d103db5..3abf93770 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "State.h" namespace dev @@ -36,28 +37,6 @@ namespace dev namespace eth { -struct WorkPackage -{ - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; -}; - -static const WorkPackage NullWorkPackage; - -/** - * @brief Describes the progress of a mining operation. - */ -struct MineProgress -{ - void combine(MineProgress const& _m) { requirement = std::max(requirement, _m.requirement); best = std::min(best, _m.best); current = std::max(current, _m.current); hashes += _m.hashes; ms = std::max(ms, _m.ms); } - double requirement = 0; ///< The PoW requirement - as the second logarithm of the minimum acceptable hash. - double best = 1e99; ///< The PoW achievement - as the second logarithm of the minimum found hash. - double current = 0; ///< The most recent PoW achievement - as the second logarithm of the presently found hash. - unsigned hashes = 0; ///< Total number of hashes computed. - unsigned ms = 0; ///< Total number of milliseconds of mining thus far. -}; - /** * @brief Class for hosting one or more Miners. * @warning Must be implemented in a threadsafe manner since it will be called from multiple @@ -66,10 +45,6 @@ struct MineProgress class MinerHost { public: - // ============================= NEW API ============================= - virtual WorkPackage const& getWork() const { return NullWorkPackage; } - - // ============================= OLD API ============================= virtual void setupState(State& _s) = 0; ///< Reset the given State object to the one that should be being mined. virtual void onProgressed() {} ///< Called once some progress has been made. virtual void onComplete() {} ///< Called once a block is found. @@ -77,17 +52,17 @@ public: virtual bool turbo() const = 0; ///< @returns true iff the Miner should use GPU if possible. }; -class Miner +class OldMiner { public: - virtual ~Miner(); + virtual ~OldMiner(); virtual void noteStateChange() = 0; virtual bool isComplete() const = 0; virtual bytes const& blockData() const = 0; }; -class AsyncMiner: public Miner +class AsyncMiner: public OldMiner { public: /// Null constructor. @@ -187,69 +162,5 @@ private: std::list m_mineHistory; ///< What the history of our mining? }; -/** - * @brief A collective of Miners. - * Miners ask for work, then submit proofs - * @threadsafe - */ -class Farm: public MinerHost -{ -public: - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi); - - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU(); - - /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. - */ - bool startGPU(); - - /** - * @brief Stop all mining activities. - */ - void stop(); - - /** - * @brief Get information on the progress of mining this work package. - * @return The progress with mining so far. - */ - MineProgress const& mineProgress() const { ReadGuard l(x_progress); return m_progress; } - -protected: - /** - * @brief Called by a Miner to retrieve a work package. Reimplemented from MinerHost. - * @return The work package to solve. - */ - virtual WorkPackage const& getWork() const override { ReadGuard l(x_work); return m_work; } - - /** - * @brief Called from a Miner to note a WorkPackage has a solution. - * @param _p The solution. - * @param _wp The WorkPackage that the Solution is for. - * @return true iff the solution was good (implying that mining should be . - */ - virtual bool submitProof(ProofOfWork::Solution const& _p, WorkPackage const& _wp) = 0; - -private: - mutable SharedMutex x_miners; - std::vector> m_miners; - - mutable SharedMutex x_progress; - MineProgress m_progress; - - mutable SharedMutex x_work; - WorkPackage m_work; -}; - - } } diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index 38f3b9429..7c72f53e8 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -28,7 +28,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) +ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb) { // Check if we already know this transaction. h256 h = sha3(_transactionRLP); @@ -50,7 +50,8 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP) // If valid, append to blocks. m_current[h] = t; m_known.insert(h); - + if (_cb) + m_callbacks[h] = _cb; ctxq << "Queued vaguely legit-looking transaction" << h.abridged(); } catch (Exception const& _e) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index 73ce24fbd..ad093b4e5 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -21,6 +21,7 @@ #pragma once +#include #include #include #include @@ -45,8 +46,10 @@ struct TransactionQueueChannel: public LogChannel { static const char* name() { class TransactionQueue { public: - ImportResult import(bytes const& _tx) { return import(&_tx); } - ImportResult import(bytesConstRef _tx); + using ImportCallback = std::function; + + ImportResult import(bytes const& _tx, ImportCallback const& _cb = ImportCallback()) { return import(&_tx); } + ImportResult import(bytesConstRef _tx, ImportCallback const& _cb = ImportCallback()); void drop(h256 _txHash); @@ -59,10 +62,11 @@ public: void clear() { WriteGuard l(m_lock); m_known.clear(); m_current.clear(); m_unknown.clear(); } private: - mutable boost::shared_mutex m_lock; ///< General lock. - std::set m_known; ///< Hashes of transactions in both sets. - std::map m_current; ///< Map of SHA3(tx) to tx. + mutable boost::shared_mutex m_lock; ///< General lock. + std::set m_known; ///< Hashes of transactions in both sets. + std::map m_current; ///< Map of SHA3(tx) to tx. std::multimap> m_unknown; ///< For transactions that have a future nonce; we map their sender address to the tx stuff, and insert once the sender has a valid TX. + std::map> m_callbacks; ///< Called once }; } diff --git a/libethereumx/Ethereum.h b/libethereumx/Ethereum.h index 7ff685339..15f00f4ae 100644 --- a/libethereumx/Ethereum.h +++ b/libethereumx/Ethereum.h @@ -52,7 +52,7 @@ class Client; */ class Ethereum { - friend class Miner; + friend class OldMiner; public: /// Constructor. After this, everything should be set up to go.