diff --git a/CMakeLists.txt b/CMakeLists.txt index 43ee58eaa..dffdd9027 100644 --- a/CMakeLists.txt +++ b/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) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a4c8a7b60..08117e596 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1362,7 +1362,7 @@ void Main::on_blocks_currentItemChanged() s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << ""; s << "
Difficulty: " << info.difficulty << ""; if (info.number) - s << "
Proof-of-Work: " << ProofOfWork::eval(info.headerHash(WithoutNonce), info.nonce) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << ""; + s << "
Proof-of-Work: " << ProofOfWork::eval(info) << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << ""; else s << "
Proof-of-Work: Phil has nothing to prove"; s << "
Parent: " << info.parentHash << ""; diff --git a/eth/CMakeLists.txt b/eth/CMakeLists.txt index bc458a50f..64cee3e12 100644 --- a/eth/CMakeLists.txt +++ b/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 (WIN32) add_custom_command(TARGET ${EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy ${MHD_DLL_RELEASE} "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 9edeacccb..764b3454e 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using bytesConstRef = vector_ref; // Numeric types. using bigint = boost::multiprecision::number>; +using u64 = boost::multiprecision::number>; using u128 = boost::multiprecision::number>; using u256 = boost::multiprecision::number>; using s256 = boost::multiprecision::number>; diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 3cdf3b449..2c9fd30ef 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -96,7 +96,10 @@ template 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. diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index feb4121cb..288dbd1ff 100644 --- a/libdevcore/CommonIO.cpp +++ b/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()); +} + diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h index 23092b702..5769b6c64 100644 --- a/libdevcore/CommonIO.h +++ b/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. diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index eec988d76..7fa5b411a 100644 --- a/libdevcore/FixedHash.h +++ b/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; using h256s = std::vector; using h160s = std::vector; diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 49ed1578b..6c645372e 100644 --- a/libethcore/BlockInfo.cpp +++ b/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(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - nonce = _header[field = 13].toHash(); + seedHash = _header[field = 13].toHash(); + mixBytes = _header[field = 14].toHash(); + nonce = _header[field = 15].toHash(); } 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) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 99efc6a17..fbc459b76 100644 --- a/libethcore/BlockInfo.h +++ b/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; } diff --git a/libethcore/CMakeLists.txt b/libethcore/CMakeLists.txt index 920f9f652..88308b630 100644 --- a/libethcore/CMakeLists.txt +++ b/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) diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index ad41780e9..822ede5aa 100644 --- a/libethcore/CommonEth.cpp +++ b/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 diff --git a/libethcore/CommonEth.h b/libethcore/CommonEth.h index 89ca0aa06..edefda380 100644 --- a/libethcore/CommonEth.h +++ b/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; + } } diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 4679c1961..5a8a2d055 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -22,6 +22,7 @@ #pragma once #include +#include "CommonEth.h" namespace dev { @@ -64,7 +65,7 @@ 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): 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(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; 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 {}; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 181e379b5..084225a38 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,12 +20,18 @@ */ #include +#include #include #include #include #include +#include +#include #include +#include #include +#include +#include "BlockInfo.h" #include "ProofOfWork.h" using namespace std; using namespace std::chrono; @@ -35,72 +41,144 @@ namespace dev namespace eth { -template -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 m_caches; + std::map m_fulls; +}; -template -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 -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 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 ret; + static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(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(ðashReturn, d, &p, h.data(), tryNonce); + u256 val(h256(ethashReturn.result, h256::ConstructFromPointer)); + best = std::min(best, log2((double)val)); + if (val <= boundary) + { + ret.first.completed = true; + result.mixHash = *reinterpret_cast(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; } } diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index c3c3f192b..7b9787f61 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -28,6 +28,7 @@ #include #include #include "CommonEth.h" +#include "BlockInfo.h" #define FAKE_DAGGER 1 @@ -45,47 +46,63 @@ struct MineInfo bool completed = false; }; -template -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 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 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 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 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; -using ProofOfWork = SHA3ProofOfWork; +using ProofOfWork = Ethash; template -std::pair ProofOfWorkEngine::mine(h256 const& _root, u256 const& _difficulty, unsigned _msTimeout, bool _continue, bool _turbo) +std::pair::Proof> ProofOfWorkEngine::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo) { - std::pair ret; + auto headerHashWithoutNonce = _header.headerHash(WithoutNonce); + auto difficulty = _header.difficulty; + + std::pair ret; static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); - 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 ProofOfWorkEngine::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::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::Proof)s; + auto e = (bigint)(u256)Evaluator::eval(headerHashWithoutNonce, solution); best = std::min(best, log2((double)e)); if (e <= d) { @@ -114,7 +131,11 @@ std::pair ProofOfWorkEngine::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; } diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 29fdc9acc..418373745 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/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(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 73e1092af..e27be90e0 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -500,10 +500,10 @@ pair 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() diff --git a/libethereum/Client.h b/libethereum/Client.h index 7cd520ab6..03debb750 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -145,7 +145,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(); } @@ -294,8 +294,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 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: diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 847c181e0..2a9de14d1 100644 --- a/libethereum/Interface.h +++ b/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 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; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index a9837d118..fcb84821b 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -255,7 +255,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) @@ -546,7 +546,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) if (rlp[2].itemCount() > 2) BOOST_THROW_EXCEPTION(TooManyUncles()); - set nonces = { m_currentBlock.nonce }; + set nonces = { m_currentBlock.nonce }; Addresses rewarded; set knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash); @@ -773,23 +773,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(); diff --git a/libethereum/State.h b/libethereum/State.h index a496a4a03..33843c65c 100644 --- a/libethereum/State.h +++ b/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. diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index dbf3b2ec9..382115ba2 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -457,9 +457,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), jsToFixed<32>(_mixHash)}); } int WebThreeStubServerBase::eth_register(std::string const& _address) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 9535c33a0..993c82c5c 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/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); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index e40c68acd..bb84afc9b 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -54,7 +54,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(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::AbstractServereth_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 getWork() override { return std::pair(); } - 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; diff --git a/test/block.cpp b/test/block.cpp index fdf65affa..4441da299 100644 --- a/test/block.cpp +++ b/test/block.cpp @@ -131,8 +131,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); @@ -211,7 +215,7 @@ 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; @@ -220,7 +224,7 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) if (o["blockHeader"].get_obj().size() != 14) { - BlockInfo tmp = current_BlockHeader; + BlockInfo tmp = currentBlockHeader; if (o["blockHeader"].get_obj().count("parentHash")) tmp.parentHash = h256(o["blockHeader"].get_obj()["parentHash"].get_str()); @@ -263,14 +267,18 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // find new valid nonce - if (tmp != current_BlockHeader) + if (tmp != currentBlockHeader) { - current_BlockHeader = tmp; + currentBlockHeader = tmp; cout << "new header!\n"; ProofOfWork pow; MineInfo ret; - while (!ProofOfWork::verify(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.nonce, current_BlockHeader.difficulty)) - tie(ret, current_BlockHeader.nonce) = pow.mine(current_BlockHeader.headerHash(WithoutNonce), current_BlockHeader.difficulty, 10000, true, true); + ProofOfWork::Proof proof; + while (!ProofOfWork::verify(currentBlockHeader)) + { + tie(ret, proof) = pow.mine(currentBlockHeader, 10000, true, true); + ProofOfWork::assignResult(proof, currentBlockHeader); + } } } else @@ -278,27 +286,27 @@ void doBlockTests(json_spirit::mValue& _v, bool _fillin) // take the blockheader as is const bytes c_blockRLP = createBlockRLPFromFields(o["blockHeader"].get_obj()); const RLP c_bRLP(c_blockRLP); - current_BlockHeader.populateFromHeader(c_bRLP, false); + 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; @@ -318,7 +326,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()); diff --git a/test/dagger.cpp b/test/dagger.cpp index 9422b6a96..87c49bd7d 100644 --- a/test/dagger.cpp +++ b/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(steady_clock::now() - s).count() << " ms" << endl; } +#endif return 0; } diff --git a/test/webthreestubclient.h b/test/webthreestubclient.h index 70aa9db99..6d97ea67a 100644 --- a/test/webthreestubclient.h +++ b/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();