Browse Source

libethcore on a new path.

cl-refactor
Gav Wood 9 years ago
parent
commit
02557813a9
  1. 41
      exp/main.cpp
  2. 104
      libethcore/BasicAuthority.cpp
  3. 91
      libethcore/BasicAuthority.h
  4. 116
      libethcore/BlockInfo.cpp
  5. 113
      libethcore/BlockInfo.h
  6. 349
      libethcore/Ethash.cpp
  7. 138
      libethcore/Ethash.h
  8. 68
      libethcore/Farm.h
  9. 22
      libethcore/ProofOfWork.cpp
  10. 80
      libethcore/ProofOfWork.h
  11. 26
      libethcore/Sealer.cpp
  12. 58
      libethcore/Sealer.h
  13. 2
      libethereum/BlockChain.cpp
  14. 5
      libethereum/Client.cpp
  15. 4
      libethereum/Client.h

41
exp/main.cpp

@ -34,6 +34,7 @@
#include <functional>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#if 0
#include <libdevcore/TrieDB.h>
#include <libdevcore/TrieHash.h>
#include <libdevcore/RangeMask.h>
@ -50,7 +51,6 @@
#include <libdevcore/FileSystem.h>
#include <libethereum/All.h>
#include <libethcore/KeyManager.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
@ -65,9 +65,48 @@ using namespace dev::p2p;
using namespace dev::shh;
namespace js = json_spirit;
namespace fs = boost::filesystem;
#else
#include <libethcore/Sealer.h>
#include <libethcore/BasicAuthority.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
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);

104
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 <http://www.gnu.org/licenses/>.
*/
/** @file BasicAuthority.cpp
* @author Gav Wood <i@gavwood.com>
* @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<Signature>();
// 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<void(SealFace const* s)> const& _f) { m_onSealGenerated = _f; }
bool isMining() const { return false; }
MiningProgress miningProgress() const { return MiningProgress(); }
private:
Secret m_secret;
std::function<void(SealFace const* s)> m_onSealGenerated;
};
SealEngineFace* createSealEngine()
{
return new BasicAuthoritySealEngine;
}

91
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 <http://www.gnu.org/licenses/>.
*/
/** @file BasicAuthority.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libdevcrypto/Common.h>
#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<BlockHeaderRaw>;
static const Address Authority;
};
}
}

116
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<h256>(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash<h256>(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash<Address>(RLP::VeryStrict);
@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
gasUsed = _header[field = 10].toInt<u256>();
timestamp = _header[field = 11].toInt<u256>();
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());

113
libethcore/BlockInfo.h

@ -23,8 +23,9 @@
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#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 BlockInfoSub>
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);
}
};
}
}

349
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<h256>();
m_nonce = _header[BlockInfo::BasicFields + 1].toHash<h64>();
void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field)
{
mixHash = _header[_field].toHash<h256>(RLP::VeryStrict);
nonce = _header[++_field].toHash<Nonce>(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<int(unsigned)> 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<int(unsigned)> const& _f) const
{
EthashAux::full(seedHash(), true, _f);
}
class EthashCPUMiner: public GenericMiner<Ethash>, Worker
{
public:
EthashCPUMiner(GenericMiner<Ethash>::ConstructionInfo const& _ci): GenericMiner<Ethash>(_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<uint64_t>) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_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<Ethash>, 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<uint64_t> _currentBlock
);
static void setNumInstances(unsigned _instances) { s_numInstances = std::min<unsigned>(_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<string, GenericFarm<Ethash>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<Ethash>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<Ethash>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<Ethash>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<Ethash>::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<void(SealFace const*)> 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<Ethash> 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<decltype(tid)>()(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*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break;
if (!(hashCount % 100))
accumulateHashes(100);
@ -243,7 +364,7 @@ static string jsonEncode(map<string, string> 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<bool> 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,

138
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<Ethash>;
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<int(unsigned)> const& _f = std::function<int(unsigned)>());
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<unsigned>(_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<int(unsigned)> const& _f = std::function<int(unsigned)>()) 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<unsigned>(_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<BlockHeaderRaw>;
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<Ethash>
{
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;
};
};
}

68
libethcore/Farm.h

@ -49,17 +49,17 @@ public:
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
struct SealerDescriptor
{
std::function<unsigned()> instances;
std::function<Miner*(typename Miner::ConstructionInfo ci)> 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<typename PoW::CPUMiner>(); }
void setSealers(std::map<std::string, SealerDescriptor> 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<typename PoW::GPUMiner>(); }
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<Miner>(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 <class MinerType>
bool start()
{
WriteGuard l(x_minerWork);
cdebug << "start()";
if (!m_miners.empty() && !!std::dynamic_pointer_cast<MinerType>(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<Miner>(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<std::string, SealerDescriptor> m_sealers;
std::string m_lastSealer;
};
}

22
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))});
}

80
libethcore/ProofOfWork.h

@ -27,91 +27,13 @@
#include <libdevcrypto/Common.h>
#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<dev::Signature>(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<int(unsigned)> const& = std::function<int(unsigned)>()) {}
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<void(Solution const& s)> const& _f) { m_onSolutionFound = _f; }
bool isMining() const { return false; }
MiningProgress miningProgress() const { return MiningProgress(); }
private:
Secret m_secret;
std::function<void(Solution const& s)> m_onSolutionFound;
};
};
using ProofOfWork = BasicAuthority;
}

26
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 <http://www.gnu.org/licenses/>.
*/
/** @file Sealer.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Sealer.h"
using namespace std;
using namespace dev;
using namespace eth;

58
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 <http://www.gnu.org/licenses/>.
*/
/** @file Sealer.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <functional>
#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<void(SealFace const* s)> const& _f) = 0;
virtual void disable() {}
// TODO: rename & generalise
virtual bool isMining() const { return false; }
virtual MiningProgress miningProgress() const { return MiningProgress(); }
};
}
}

2
libethereum/BlockChain.cpp

@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
BlockInfo bi(b);
if (_prepPoW)
ProofOfWork::prep(bi);
Ethash::prep(bi);
if (bi.parentHash != lastHash)
{

5
libethereum/Client.cpp

@ -22,6 +22,7 @@
#include "Client.h"
#include <chrono>
#include <memory>
#include <thread>
#include <boost/filesystem.hpp>
#if ETH_JSONRPC || !ETH_TRUE
@ -31,6 +32,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/StructuredLogger.h>
#include <libp2p/Host.h>
#include <libethcore/Ethash.h>
#if ETH_JSONRPC || !ETH_TRUE
#include "Sentinel.h"
#endif
@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _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<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); });
m_gp->update(m_bc);

4
libethereum/Client.h

@ -36,8 +36,8 @@
#include <libdevcore/Guards.h>
#include <libdevcore/Worker.h>
#include <libethcore/Params.h>
#include <libethcore/Sealer.h>
#include <libethcore/ABI.h>
#include <libethcore/Farm.h>
#include <libp2p/Common.h>
#include "CanonBlockChain.h"
#include "TransactionQueue.h"
@ -310,7 +310,7 @@ private:
std::weak_ptr<EthereumHost> m_host; ///< Our Ethereum Host. Don't do anything if we can't lock.
ProofOfWork::Farm m_farm; ///< Our mining farm.
std::shared_ptr<SealEngineFace> m_sealEngine; ///< Our block-sealing engine.
Handler<> m_tqReady;
Handler<> m_bqReady;

Loading…
Cancel
Save