From 3146cf6cb7212042836ac91b9455f8c248e1e142 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + 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 BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + 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 BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#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() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -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; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -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 + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (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( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ 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; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } + static std::string platformInfo(); + static void listDevices() {} + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } + +protected: + void kickOff() override + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } - static std::string platformInfo(); - static void listDevices() {} - static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#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/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - 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(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ 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 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -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/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + 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 Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + 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 Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady;