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();