diff --git a/eth/main.cpp b/eth/main.cpp index 67058a473..1e724c7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1702,7 +1702,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) {