Browse Source

New Proof-of-Work.

cl-refactor
Gav Wood 10 years ago
parent
commit
49b9a0224a
  1. 3
      CMakeLists.txt
  2. 2
      alethzero/MainWin.cpp
  3. 2
      eth/CMakeLists.txt
  4. 1
      libdevcore/Common.h
  5. 5
      libdevcore/CommonData.h
  6. 23
      libdevcore/CommonIO.cpp
  7. 4
      libdevcore/CommonIO.h
  8. 1
      libdevcore/FixedHash.h
  9. 20
      libethcore/BlockInfo.cpp
  10. 8
      libethcore/BlockInfo.h
  11. 1
      libethcore/CMakeLists.txt
  12. 2
      libethcore/CommonEth.cpp
  13. 2
      libethcore/CommonEth.h
  14. 5
      libethcore/Exceptions.h
  15. 182
      libethcore/ProofOfWork.cpp
  16. 67
      libethcore/ProofOfWork.h
  17. 4
      libethereum/CanonBlockChain.cpp
  18. 4
      libethereum/Client.cpp
  19. 6
      libethereum/Client.h
  20. 2
      libethereum/Interface.h
  21. 21
      libethereum/State.cpp
  22. 2
      libethereum/State.h
  23. 4
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  24. 2
      libweb3jsonrpc/WebThreeStubServerBase.h
  25. 6
      libweb3jsonrpc/abstractwebthreestubserver.h
  26. 2
      libweb3jsonrpc/spec.json
  27. 2
      mix/MixClient.h
  28. 112
      test/block.cpp
  29. 2
      test/dagger.cpp
  30. 3
      test/webthreestubclient.h

3
CMakeLists.txt

@ -60,7 +60,7 @@ function(configureProject)
endif()
endfunction()
set(CPPETHEREUM 1)
function(createBuildInfo)
# Set build platform; to be written to BuildInfo.h
@ -174,6 +174,7 @@ add_subdirectory(libp2p)
add_subdirectory(libdevcrypto)
add_subdirectory(libwhisper)
add_subdirectory(libethash)
add_subdirectory(libethcore)
add_subdirectory(libevm)
add_subdirectory(libethereum)

2
alethzero/MainWin.cpp

@ -1366,7 +1366,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>";
s << "<br/>Difficulty: <b>" << info.difficulty << "</b>";
if (info.number)
s << "<br/>Proof-of-Work: <b>" << ProofOfWork::eval(info.headerHash(WithoutNonce), info.nonce) << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b>";
s << "<br/>Proof-of-Work: <b>" << ProofOfWork::eval(info) << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b>";
else
s << "<br/>Proof-of-Work: <i>Phil has nothing to prove</i>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>";

2
eth/CMakeLists.txt

@ -26,7 +26,7 @@ if (JSONRPC)
endif()
target_link_libraries(${EXECUTABLE} webthree)
target_link_libraries(${EXECUTABLE} secp256k1)
target_link_libraries(${EXECUTABLE} ethash)
if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW)
add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")

1
libdevcore/Common.h

@ -65,6 +65,7 @@ using bytesConstRef = vector_ref<byte const>;
// Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u64 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;

5
libdevcore/CommonData.h

@ -96,7 +96,10 @@ template <class _T, class _Out>
inline void toBigEndian(_T _val, _Out& o_out)
{
for (auto i = o_out.size(); i-- != 0; _val >>= 8)
o_out[i] = (typename _Out::value_type)(uint8_t)_val;
{
_T v = _val & (_T)0xff;
o_out[i] = (typename _Out::value_type)(uint8_t)v;
}
}
/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.

23
libdevcore/CommonIO.cpp

@ -57,6 +57,24 @@ string dev::memDump(bytes const& _bytes, unsigned _width, bool _html)
return ret.str();
}
// Don't forget to delete[] later.
bytesRef dev::contentsNew(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return bytesRef();
// get length of file:
is.seekg (0, is.end);
streamoff length = is.tellg();
if (length == 0) // return early, MSVC does not like reading 0 bytes
return bytesRef();
is.seekg (0, is.beg);
bytesRef ret(new byte[length], length);
is.read((char*)ret.data(), length);
is.close();
return ret;
}
bytes dev::contents(std::string const& _file)
{
std::ifstream is(_file, std::ifstream::binary);
@ -79,3 +97,8 @@ void dev::writeFile(std::string const& _file, bytes const& _data)
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}
void dev::writeFile(std::string const& _file, bytesConstRef _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

4
libdevcore/CommonIO.h

@ -42,9 +42,13 @@ namespace dev
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file);
/// Retrieve and returns the allocated contents of the given file. If the file doesn't exist or isn't readable, returns nullptr. Don't forget to delete [] when finished.
bytesRef contentsNew(std::string const& _file);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
void writeFile(std::string const& _file, bytes const& _data);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
void writeFile(std::string const& _file, bytesConstRef _data);
/// Nicely renders the given bytes to a string, optionally as HTML.
/// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line.

1
libdevcore/FixedHash.h

@ -247,6 +247,7 @@ using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h128 = FixedHash<16>;
using h64 = FixedHash<8>;
using h512s = std::vector<h512>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;

20
libethcore/BlockInfo.cpp

@ -30,7 +30,7 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
u256 dev::eth::c_genesisDifficulty = (u256)1 << 17;
u256 dev::eth::c_genesisDifficulty = (u256)1 << 11;
BlockInfo::BlockInfo(): timestamp(Invalid256)
{
@ -56,7 +56,9 @@ void BlockInfo::setEmpty()
gasUsed = 0;
timestamp = 0;
extraData.clear();
nonce = h256();
seedHash = h256();
mixBytes = h256();
nonce = Nonce();
hash = headerHash(WithNonce);
}
@ -76,11 +78,11 @@ h256 BlockInfo::headerHash(IncludeNonce _n) const
void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const
{
_s.appendList(_n == WithNonce ? 14 : 13)
_s.appendList(_n == WithNonce ? 16 : 14)
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData;
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData << seedHash;
if (_n == WithNonce)
_s << nonce;
_s << mixBytes << nonce;
}
h256 BlockInfo::headerHash(bytesConstRef _block)
@ -108,7 +110,9 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
gasUsed = _header[field = 10].toInt<u256>();
timestamp = _header[field = 11].toInt<u256>();
extraData = _header[field = 12].toBytes();
nonce = _header[field = 13].toHash<h256>();
seedHash = _header[field = 13].toHash<h256>();
mixBytes = _header[field = 14].toHash<h256>();
nonce = _header[field = 15].toHash<Nonce>();
}
catch (Exception const& _e)
@ -118,7 +122,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
}
// check it hashes according to proof of work or that it's the genesis block.
if (_checkNonce && parentHash && !ProofOfWork::verify(headerHash(WithoutNonce), nonce, difficulty))
if (_checkNonce && parentHash && !ProofOfWork::verify(*this))
BOOST_THROW_EXCEPTION(InvalidBlockNonce(headerHash(WithoutNonce), nonce, difficulty));
if (gasUsed > gasLimit)
@ -176,6 +180,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent)
gasLimit = calculateGasLimit(_parent);
gasUsed = 0;
difficulty = calculateDifficulty(_parent);
seedHash = number % 30 == 0 ? sha3(_parent.seedHash.asBytes() /*+ _parent.hash.asBytes()*/) : _parent.seedHash;
}
u256 BlockInfo::calculateGasLimit(BlockInfo const& _parent) const
@ -204,7 +209,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
if (diff(gasLimit, _parent.gasLimit) <= _parent.gasLimit / 1024)
BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, calculateGasLimit(_parent), diff(gasLimit, _parent.gasLimit), _parent.gasLimit / 1024));
// Check timestamp is after previous timestamp.
if (parentHash)
{

8
libethcore/BlockInfo.h

@ -76,7 +76,9 @@ public:
u256 gasUsed;
u256 timestamp;
bytes extraData;
h256 nonce;
h256 mixBytes;
h256 seedHash;
Nonce nonce;
BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {}
@ -104,6 +106,8 @@ public:
gasUsed == _cmp.gasUsed &&
timestamp == _cmp.timestamp &&
extraData == _cmp.extraData &&
mixBytes == _cmp.mixBytes &&
seedHash == _cmp.seedHash &&
nonce == _cmp.nonce;
}
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
@ -129,7 +133,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{
_out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " <<
_bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " <<
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce;
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixBytes << " " << _bi.seedHash << " " << _bi.nonce;
return _out;
}

1
libethcore/CMakeLists.txt

@ -22,6 +22,7 @@ else()
add_library(${EXECUTABLE} SHARED ${SRC_LIST} ${HEADERS})
endif()
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcrypto)
target_link_libraries(${EXECUTABLE} devcore)

2
libethcore/CommonEth.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 55;
const unsigned c_protocolVersion = 56;
const unsigned c_databaseVersion = 6 +
#if ETH_FATDB
1000

2
libethcore/CommonEth.h

@ -66,5 +66,7 @@ static const u256 finney = exp10<15>();
static const u256 szabo = exp10<12>();
static const u256 wei = exp10<0>();
using Nonce = h64;
}
}

5
libethcore/Exceptions.h

@ -22,6 +22,7 @@
#pragma once
#include <libdevcore/Exceptions.h>
#include "CommonEth.h"
namespace dev
{
@ -63,8 +64,8 @@ struct InvalidTransactionsStateRoot: virtual dev::Exception {};
struct InvalidReceiptsStateRoot: virtual dev::Exception {};
struct InvalidTimestamp: virtual dev::Exception {};
struct InvalidLogBloom: virtual dev::Exception {};
class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0); u256 required; u256 candidate; };
class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0); h256 h; h256 n; u256 d; };
class InvalidNonce: virtual public dev::Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual const char* what() const noexcept; };
class InvalidBlockNonce: virtual public dev::Exception { public: InvalidBlockNonce(h256 _h = h256(), Nonce _n = Nonce(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; Nonce n; u256 d; virtual const char* what() const noexcept; };
struct InvalidParentHash: virtual dev::Exception {};
struct InvalidNumber: virtual dev::Exception {};
struct InvalidContractAddress: virtual public dev::Exception {};

182
libethcore/ProofOfWork.cpp

@ -20,12 +20,18 @@
*/
#include <boost/detail/endian.hpp>
#include <boost/filesystem.hpp>
#include <chrono>
#include <array>
#include <random>
#include <thread>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/Common.h>
#include <libethash/ethash.h>
#include "BlockInfo.h"
#include "ProofOfWork.h"
using namespace std;
using namespace std::chrono;
@ -35,72 +41,144 @@ namespace dev
namespace eth
{
template <class _T>
static inline void update(_T& _sha, u256 const& _value)
class Ethasher
{
int i = 0;
for (u256 v = _value; v; ++i, v >>= 8) {}
byte buf[32];
bytesRef bufRef(buf, i);
toBigEndian(_value, bufRef);
_sha.Update(buf, i);
}
public:
Ethasher() {}
static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; }
bytes const& cache(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (!m_caches.count(_header.seedHash))
{
try {
boost::filesystem::create_directories(getDataDir() + "/ethashcache");
} catch (...) {}
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".cache";
m_caches[_header.seedHash] = contents(memoFile);
if (m_caches[_header.seedHash].empty())
{
ethash_params p = params((unsigned)_header.number);
m_caches[_header.seedHash].resize(p.cache_size);
ethash_prep_light(m_caches[_header.seedHash].data(), &p, _header.seedHash.data());
writeFile(memoFile, m_caches[_header.seedHash]);
}
}
return m_caches[_header.seedHash];
}
byte const* full(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (!m_fulls.count(_header.seedHash))
{
if (!m_fulls.empty())
{
delete [] m_fulls.begin()->second.data();
m_fulls.erase(m_fulls.begin());
}
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".full";
m_fulls[_header.seedHash] = contentsNew(memoFile);
if (!m_fulls[_header.seedHash])
{
ethash_params p = params((unsigned)_header.number);
m_fulls[_header.seedHash] = bytesRef(new byte[p.full_size], p.full_size);
auto c = cache(_header);
ethash_prep_full(m_fulls[_header.seedHash].data(), &p, c.data());
writeFile(memoFile, m_fulls[_header.seedHash]);
}
}
return m_fulls[_header.seedHash].data();
}
static ethash_params params(BlockInfo const& _header)
{
return params((unsigned)_header.number);
}
static ethash_params params(unsigned _n)
{
ethash_params p;
p.cache_size = ethash_get_cachesize(_n);
p.full_size = ethash_get_datasize(_n);
return p;
}
private:
static Ethasher* s_this;
RecursiveMutex x_this;
std::map<h256, bytes> m_caches;
std::map<h256, bytesRef> m_fulls;
};
template <class _T>
static inline void update(_T& _sha, h256 const& _value)
Ethasher* Ethasher::s_this = nullptr;
bool Ethash::verify(BlockInfo const& _header)
{
int i = 0;
byte const* data = _value.data();
for (; i != 32 && data[i] == 0; ++i);
_sha.Update(data + i, 32 - i);
bigint boundary = (bigint(1) << 256) / _header.difficulty;
u256 e(eval(_header, _header.nonce));
return e <= boundary;
}
template <class _T>
static inline h256 get(_T& _sha)
h256 Ethash::eval(BlockInfo const& _header, Nonce const& _nonce)
{
h256 ret;
_sha.TruncatedFinal(&ret[0], 32);
return ret;
auto p = Ethasher::params(_header);
ethash_return_value r;
ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce);
return h256(r.result, h256::ConstructFromPointer);
}
h256 DaggerEvaluator::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i)
std::pair<MineInfo, Ethash::Proof> Ethash::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo)
{
if (_L == _i)
return _root;
u256 m = (_L == 9) ? 16 : 3;
CryptoPP::SHA3_256 bsha;
for (uint_fast32_t k = 0; k < m; ++k)
auto h = _header.headerHash(WithoutNonce);
auto p = Ethasher::params(_header);
auto d = Ethasher::get()->full(_header);
std::pair<MineInfo, Proof> ret;
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data())));
uint64_t tryNonce = (uint64_t)(u64)(m_last = Nonce::random(s_eng));
bigint boundary = (bigint(1) << 256) / _header.difficulty;
ret.first.requirement = log2((double)boundary);
// 2^ 0 32 64 128 256
// [--------*-------------------------]
//
// evaluate until we run out of time
auto startTime = std::chrono::steady_clock::now();
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
double best = 1e99; // high enough to be effectively infinity :)
Proof result;
ethash_return_value ethashReturn;
unsigned hashCount = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++)
{
CryptoPP::SHA3_256 sha;
update(sha, _root);
update(sha, _xn);
update(sha, (u256)_L);
update(sha, (u256)_i);
update(sha, (u256)k);
uint_fast32_t pk = (uint_fast32_t)(u256)get(sha) & ((1 << ((_L - 1) * 3)) - 1);
auto u = node(_root, _xn, _L - 1, pk);
update(bsha, u);
ethash_compute_full(&ethashReturn, d, &p, h.data(), tryNonce);
u256 val(h256(ethashReturn.result, h256::ConstructFromPointer));
best = std::min<double>(best, log2((double)val));
if (val <= boundary)
{
ret.first.completed = true;
result.mixHash = *reinterpret_cast<h256 const*>(ethashReturn.mix_hash);
result.nonce = u64(tryNonce);
break;
}
}
return get(bsha);
}
ret.first.hashes = hashCount;
ret.first.best = best;
ret.second = result;
h256 DaggerEvaluator::eval(h256 const& _root, h256 const& _nonce)
{
h256 extranonce = (u256)_nonce >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26)
CryptoPP::SHA3_256 bsha;
for (uint_fast32_t k = 0; k < 4; ++k)
if (ret.first.completed)
{
//sha256(D || xn || i || k) -> sha256(D || xn || k) - there's no 'i' here!
CryptoPP::SHA3_256 sha;
update(sha, _root);
update(sha, extranonce);
update(sha, _nonce);
update(sha, (u256)k);
uint_fast32_t pk = (uint_fast32_t)(u256)get(sha) & 0x1ffffff; // mod 8^8 * 2 [ == mod 2^25 ?! ] [ == & ((1 << 25) - 1) ] [ == & 0x1ffffff ]
auto u = node(_root, extranonce, 9, pk);
update(bsha, u);
BlockInfo test = _header;
assignResult(result, test);
assert(verify(test));
}
return get(bsha);
return ret;
}
}

67
libethcore/ProofOfWork.h

@ -28,6 +28,7 @@
#include <cstdint>
#include <libdevcrypto/SHA3.h>
#include "CommonEth.h"
#include "BlockInfo.h"
#define FAKE_DAGGER 1
@ -45,47 +46,63 @@ struct MineInfo
bool completed = false;
};
template <class Evaluator>
class ProofOfWorkEngine: public Evaluator
class Ethash
{
public:
static bool verify(h256 const& _root, h256 const& _nonce, u256 const& _difficulty) { return (bigint)(u256)Evaluator::eval(_root, _nonce) <= (bigint(1) << 256) / _difficulty; }
// bit-compatible with ethash_return_value
struct Proof
{
Nonce nonce;
h256 mixHash;
};
inline std::pair<MineInfo, h256> mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static h256 eval(BlockInfo const& _header) { return eval(_header, _header.nonce); }
static h256 eval(BlockInfo const& _header, Nonce const& _nonce);
static bool verify(BlockInfo const& _header);
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixBytes = _r.mixHash; }
protected:
h256 m_last;
Nonce m_last;
};
class SHA3Evaluator
template <class Evaluator>
class ProofOfWorkEngine: public Evaluator
{
public:
static h256 eval(h256 const& _root, h256 const& _nonce) { h256 b[2] = { _root, _nonce }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
};
using Proof = Nonce;
static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; }
inline std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
// TODO: class ARPoWEvaluator
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; }
class DaggerEvaluator
protected:
Nonce m_last;
};
class SHA3Evaluator
{
public:
static h256 eval(h256 const& _root, h256 const& _nonce);
private:
static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i);
static h256 eval(h256 const& _root, Nonce const& _nonce) { h256 b[2] = { _root, h256(_nonce) }; return sha3(bytesConstRef((byte const*)&b[0], 64)); }
};
using SHA3ProofOfWork = ProofOfWorkEngine<SHA3Evaluator>;
using ProofOfWork = SHA3ProofOfWork;
using ProofOfWork = Ethash;
template <class Evaluator>
std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo)
std::pair<MineInfo, typename ProofOfWorkEngine<Evaluator>::Proof> ProofOfWorkEngine<Evaluator>::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo)
{
std::pair<MineInfo, h256> ret;
auto headerHashWithoutNonce = _header.headerHash(WithoutNonce);
auto difficulty = _header.difficulty;
std::pair<MineInfo, Nonce> ret;
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data())));
u256 s = (m_last = h256::random(s_eng));
Nonce::Arith s = (m_last = Nonce::random(s_eng));
bigint d = (bigint(1) << 256) / _difficulty;
bigint d = (bigint(1) << 256) / difficulty;
ret.first.requirement = log2((double)d);
// 2^ 0 32 64 128 256
@ -96,12 +113,12 @@ std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root,
if (!_turbo)
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
double best = 1e99; // high enough to be effectively infinity :)
h256 solution;
ProofOfWorkEngine<Evaluator>::Proof solution;
unsigned h = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; s++, h++)
{
solution = (h256)s;
auto e = (bigint)(u256)Evaluator::eval(_root, solution);
solution = (ProofOfWorkEngine<Evaluator>::Proof)s;
auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution);
best = std::min<double>(best, log2((double)e));
if (e <= d)
{
@ -114,7 +131,11 @@ std::pair<MineInfo, h256> ProofOfWorkEngine<Evaluator>::mine(h256 const& _root,
ret.second = solution;
if (ret.first.completed)
assert(verify(_root, solution, _difficulty));
{
BlockInfo test = _header;
assignResult(solution, test);
assert(verify(test));
}
return ret;
}

4
libethereum/CanonBlockChain.cpp

@ -82,8 +82,8 @@ bytes CanonBlockChain::createGenesisBlock()
stateRoot = state.root();
}
block.appendList(14)
<< h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42));
block.appendList(16)
<< h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << 1000000 << 0 << (unsigned)0 << string() << h256() << h256() << Nonce(u64(42));
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();

4
libethereum/Client.cpp

@ -504,10 +504,10 @@ pair<h256, u256> Client::getWork()
return make_pair(m_remoteMiner.workHash(), m_remoteMiner.difficulty());
}
bool Client::submitNonce(h256 const&_nonce)
bool Client::submitWork(ProofOfWork::Proof const& _proof)
{
Guard l(x_remoteMiner);
return m_remoteMiner.submitWork(_nonce);
return m_remoteMiner.submitWork(_proof);
}
void Client::doWork()

6
libethereum/Client.h

@ -148,7 +148,7 @@ public:
h256 workHash() const { return m_state.info().headerHash(IncludeNonce::WithoutNonce); }
u256 const& difficulty() const { return m_state.info().difficulty; }
bool submitWork(h256 const& _nonce) { return (m_isComplete = m_state.completeMine(_nonce)); }
bool submitWork(ProofOfWork::Proof const& _result) { return (m_isComplete = m_state.completeMine(_result)); }
virtual bool isComplete() const override { return m_isComplete; }
virtual bytes const& blockData() const { return m_state.blockData(); }
@ -303,8 +303,8 @@ public:
/// Update to the latest transactions and get hash of the current block to be mined minus the
/// nonce (the 'work hash') and the difficulty to be met.
virtual std::pair<h256, u256> getWork() override;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&_nonce) override;
/// Submit the proof for the proof-of-work.
virtual bool submitWork(ProofOfWork::Proof const& _proof) override;
// Debug stuff:

2
libethereum/Interface.h

@ -154,7 +154,7 @@ public:
/// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual std::pair<h256, u256> getWork() = 0;
/// Submit the nonce for the proof-of-work.
virtual bool submitNonce(h256 const&) = 0;
virtual bool submitWork(ProofOfWork::Proof const& _proof) = 0;
/// Check the progress of the mining.
virtual MineProgress miningProgress() const = 0;

21
libethereum/State.cpp

@ -256,7 +256,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
{
auto b = _bc.block(_block);
bi.populate(b);
// bi.verifyInternals(_bc.block(_block)); // Unneeded - we already verify on import into the blockchain.
// bi.verifyInternals(_bc.block(_block)); // Unneeded - we already verify on import into the blockchain.
break;
}
catch (Exception const& _e)
@ -547,7 +547,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles());
set<h256> nonces = { m_currentBlock.nonce };
set<Nonce> nonces = { m_currentBlock.nonce };
Addresses rewarded;
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);
@ -774,23 +774,28 @@ MineInfo State::mine(unsigned _msTimeout, bool _turbo)
MineInfo ret;
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
tie(ret, m_currentBlock.nonce) = m_pow.mine(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.difficulty, _msTimeout, true, _turbo);
ProofOfWork::Proof r;
tie(ret, r) = m_pow.mine(m_currentBlock, _msTimeout, true, _turbo);
if (!ret.completed)
m_currentBytes.clear();
else
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
{
ProofOfWork::assignResult(r, m_currentBlock);
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock);
}
return ret;
}
bool State::completeMine(h256 const& _nonce)
bool State::completeMine(ProofOfWork::Proof const& _nonce)
{
if (!m_pow.verify(m_currentBlock.headerHash(WithoutNonce), _nonce, m_currentBlock.difficulty))
ProofOfWork::assignResult(_nonce, m_currentBlock);
if (!m_pow.verify(m_currentBlock))
return false;
m_currentBlock.nonce = _nonce;
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock.headerHash(WithoutNonce), m_currentBlock.nonce, m_currentBlock.difficulty);
cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce).abridged() << m_currentBlock.nonce.abridged() << m_currentBlock.difficulty << ProofOfWork::verify(m_currentBlock);
completeMine();

2
libethereum/State.h

@ -112,7 +112,7 @@ public:
/// Pass in a solution to the proof-of-work.
/// @returns true iff the given nonce is a proof-of-work for this State's block.
bool completeMine(h256 const& _nonce);
bool completeMine(ProofOfWork::Proof const& _result);
/// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening.

4
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -461,9 +461,9 @@ Json::Value WebThreeStubServerBase::eth_getWork()
return ret;
}
bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce)
bool WebThreeStubServerBase::eth_submitWork(std::string const& _nonce, std::string const& _mixHash)
{
return client()->submitNonce(jsToFixed<32>(_nonce));
return client()->submitWork(ProofOfWork::Proof{jsToFixed<Nonce::size>(_nonce), jsToFixed<32>(_mixHash)});
}
int WebThreeStubServerBase::eth_register(std::string const& _address)

2
libweb3jsonrpc/WebThreeStubServerBase.h

@ -110,7 +110,7 @@ public:
virtual bool eth_uninstallFilter(int _id);
virtual Json::Value eth_getWork();
virtual bool eth_submitWork(std::string const& _nonce);
virtual bool eth_submitWork(std::string const& _nonce, std::string const& _mixHash);
virtual int eth_register(std::string const& _address);
virtual bool eth_unregister(int _id);

6
libweb3jsonrpc/abstractwebthreestubserver.h

@ -54,7 +54,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
this->bindAndAddMethod(jsonrpc::Procedure("eth_filterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_filterLogsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_logs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_logsI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_register", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_INTEGER, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_registerI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_unregister", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_unregisterI);
this->bindAndAddMethod(jsonrpc::Procedure("eth_queuedTransactions", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_INTEGER, NULL), &AbstractWebThreeStubServer::eth_queuedTransactionsI);
@ -254,7 +254,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
}
inline virtual void eth_submitWorkI(const Json::Value &request, Json::Value &response)
{
response = this->eth_submitWork(request[0u].asString());
response = this->eth_submitWork(request[0u].asString(), request[1u].asString());
}
inline virtual void eth_registerI(const Json::Value &request, Json::Value &response)
{
@ -363,7 +363,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer<AbstractWebThr
virtual Json::Value eth_filterLogs(int param1) = 0;
virtual Json::Value eth_logs(const Json::Value& param1) = 0;
virtual Json::Value eth_getWork() = 0;
virtual bool eth_submitWork(const std::string& param1) = 0;
virtual bool eth_submitWork(const std::string& param1, const std::string& param2) = 0;
virtual int eth_register(const std::string& param1) = 0;
virtual bool eth_unregister(int param1) = 0;
virtual Json::Value eth_queuedTransactions(int param1) = 0;

2
libweb3jsonrpc/spec.json

@ -48,7 +48,7 @@
{ "name": "eth_logs", "params": [{}], "order": [], "returns": []},
{ "name": "eth_getWork", "params": [], "order": [], "returns": []},
{ "name": "eth_submitWork", "params": [""], "order": [], "returns": true},
{ "name": "eth_submitWork", "params": ["", ""], "order": [], "returns": true},
{ "name": "eth_register", "params": [""], "order": [], "returns": 0},
{ "name": "eth_unregister", "params": [0], "order": [], "returns": true},

2
mix/MixClient.h

@ -87,7 +87,7 @@ public:
bool isMining() override;
eth::MineProgress miningProgress() const override;
std::pair<h256, u256> getWork() override { return std::pair<h256, u256>(); }
bool submitNonce(h256 const&) override { return false; }
bool submitWork(eth::ProofOfWork::Proof const&) override { return false; }
/// @returns the last mined block information
eth::BlockInfo blockInfo() const;
std::vector<KeyPair> userAccounts() { return m_userAccounts; }

112
test/block.cpp

@ -201,8 +201,12 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
// find new valid nonce
ProofOfWork pow;
MineInfo ret;
while (!ProofOfWork::verify(blockFromFields.headerHash(WithoutNonce), blockFromFields.nonce, blockFromFields.difficulty))
tie(ret, blockFromFields.nonce) = pow.mine(blockFromFields.headerHash(WithoutNonce), blockFromFields.difficulty, 1000, true, true);
ProofOfWork::Proof proof;
while (!ProofOfWork::verify(blockFromFields))
{
tie(ret, proof) = pow.mine(blockFromFields, 1000, true, true);
ProofOfWork::assignResult(proof, blockFromFields);
}
//update genesis block in json file
o["genesisBlockHeader"].get_obj()["stateRoot"] = toString(blockFromFields.stateRoot);
@ -281,27 +285,97 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
o["transactions"] = txArray;
o["rlp"] = "0x" + toHex(state.blockData());
BlockInfo current_BlockHeader = state.info();
BlockInfo currentBlockHeader = state.info();
// overwrite blockheader with (possible wrong) data from "blockheader" in filler;
overwriteBlockHeader(o, current_BlockHeader);
if (o.count("blockHeader"))
{
if (o["blockHeader"].get_obj().size() != 14)
{
BlockInfo tmp = currentBlockHeader;
if (o["blockHeader"].get_obj().count("parentHash"))
tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str());
if (o["blockHeader"].get_obj().count("uncleHash"))
tmp.sha3Uncles = h256(o["blockHeader"].get_obj()["uncleHash"].get_str());
if (o["blockHeader"].get_obj().count("coinbase"))
tmp.coinbaseAddress = Address(o["blockHeader"].get_obj()["coinbase"].get_str());
if (o["blockHeader"].get_obj().count("stateRoot"))
tmp.stateRoot = h256(o["blockHeader"].get_obj()["stateRoot"].get_str());
if (o["blockHeader"].get_obj().count("transactionsTrie"))
tmp.transactionsRoot = h256(o["blockHeader"].get_obj()["transactionsTrie"].get_str());
if (o["blockHeader"].get_obj().count("receiptTrie"))
tmp.receiptsRoot = h256(o["blockHeader"].get_obj()["receiptTrie"].get_str());
if (o["blockHeader"].get_obj().count("bloom"))
tmp.logBloom = LogBloom(o["blockHeader"].get_obj()["bloom"].get_str());
if (o["blockHeader"].get_obj().count("difficulty"))
tmp.difficulty = toInt(o["blockHeader"].get_obj()["difficulty"]);
if (o["blockHeader"].get_obj().count("number"))
tmp.number = toInt(o["blockHeader"].get_obj()["number"]);
if (o["blockHeader"].get_obj().count("gasLimit"))
tmp.gasLimit = toInt(o["blockHeader"].get_obj()["gasLimit"]);
if (o["blockHeader"].get_obj().count("gasUsed"))
tmp.gasUsed = toInt(o["blockHeader"].get_obj()["gasUsed"]);
if (o["blockHeader"].get_obj().count("timestamp"))
tmp.timestamp = toInt(o["blockHeader"].get_obj()["timestamp"]);
if (o["blockHeader"].get_obj().count("extraData"))
tmp.extraData = importByteArray(o["blockHeader"].get_obj()["extraData"].get_str());
// find new valid nonce
if (tmp != currentBlockHeader)
{
currentBlockHeader = tmp;
cout << "new header!\n";
ProofOfWork pow;
MineInfo ret;
ProofOfWork::Proof proof;
while (!ProofOfWork::verify(currentBlockHeader))
{
tie(ret, proof) = pow.mine(currentBlockHeader, 10000, true, true);
ProofOfWork::assignResult(proof, currentBlockHeader);
}
}
}
else
{
// take the blockheader as is
const bytes c_blockRLP = createBlockRLPFromFields(o["blockHeader"].get_obj());
const RLP c_bRLP(c_blockRLP);
currentBlockHeader.populateFromHeader(c_bRLP, false);
}
}
// write block header
mObject oBlockHeader;
oBlockHeader["parentHash"] = toString(current_BlockHeader.parentHash);
oBlockHeader["uncleHash"] = toString(current_BlockHeader.sha3Uncles);
oBlockHeader["coinbase"] = toString(current_BlockHeader.coinbaseAddress);
oBlockHeader["stateRoot"] = toString(current_BlockHeader.stateRoot);
oBlockHeader["transactionsTrie"] = toString(current_BlockHeader.transactionsRoot);
oBlockHeader["receiptTrie"] = toString(current_BlockHeader.receiptsRoot);
oBlockHeader["bloom"] = toString(current_BlockHeader.logBloom);
oBlockHeader["difficulty"] = toString(current_BlockHeader.difficulty);
oBlockHeader["number"] = toString(current_BlockHeader.number);
oBlockHeader["gasLimit"] = toString(current_BlockHeader.gasLimit);
oBlockHeader["gasUsed"] = toString(current_BlockHeader.gasUsed);
oBlockHeader["timestamp"] = toString(current_BlockHeader.timestamp);
oBlockHeader["extraData"] = toHex(current_BlockHeader.extraData);
oBlockHeader["nonce"] = toString(current_BlockHeader.nonce);
oBlockHeader["parentHash"] = toString(currentBlockHeader.parentHash);
oBlockHeader["uncleHash"] = toString(currentBlockHeader.sha3Uncles);
oBlockHeader["coinbase"] = toString(currentBlockHeader.coinbaseAddress);
oBlockHeader["stateRoot"] = toString(currentBlockHeader.stateRoot);
oBlockHeader["transactionsTrie"] = toString(currentBlockHeader.transactionsRoot);
oBlockHeader["receiptTrie"] = toString(currentBlockHeader.receiptsRoot);
oBlockHeader["bloom"] = toString(currentBlockHeader.logBloom);
oBlockHeader["difficulty"] = toString(currentBlockHeader.difficulty);
oBlockHeader["number"] = toString(currentBlockHeader.number);
oBlockHeader["gasLimit"] = toString(currentBlockHeader.gasLimit);
oBlockHeader["gasUsed"] = toString(currentBlockHeader.gasUsed);
oBlockHeader["timestamp"] = toString(currentBlockHeader.timestamp);
oBlockHeader["extraData"] = toHex(currentBlockHeader.extraData);
oBlockHeader["nonce"] = toString(currentBlockHeader.nonce);
o["blockHeader"] = oBlockHeader;
@ -321,7 +395,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin)
}
RLPStream rlpStream2;
current_BlockHeader.streamRLP(rlpStream2, WithNonce);
currentBlockHeader.streamRLP(rlpStream2, WithNonce);
RLPStream block2(3);
block2.appendRaw(rlpStream2.out());

2
test/dagger.cpp

@ -30,6 +30,7 @@ using namespace dev::eth;
int daggerTest()
{
#if 0
cnote << "Testing ProofOfWork...";
// Test dagger
{
@ -46,6 +47,7 @@ int daggerTest()
cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1);
cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl;
}
#endif
return 0;
}

3
test/webthreestubclient.h

@ -437,10 +437,11 @@ class WebThreeStubClient : public jsonrpc::Client
else
throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString());
}
bool eth_submitWork(const std::string& param1) throw (jsonrpc::JsonRpcException)
bool eth_submitWork(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException)
{
Json::Value p;
p.append(param1);
p.append(param2);
Json::Value result = this->CallMethod("eth_submitWork",p);
if (result.isBool())
return result.asBool();

Loading…
Cancel
Save