diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp index c6e9a5374..b8ae50c84 100644 --- a/libethereum/BlockInfo.cpp +++ b/libethereum/BlockInfo.cpp @@ -91,8 +91,7 @@ void BlockInfo::populate(bytesConstRef _block) } // check it hashes according to proof of work. - Dagger d(headerHashWithoutNonce()); - if (d.eval(nonce) >= difficulty) + if (!Dagger::verify(headerHashWithoutNonce(), nonce, difficulty)) throw InvalidNonce(); } diff --git a/libethereum/Dagger.cpp b/libethereum/Dagger.cpp index f9820f969..9ad4f1eba 100644 --- a/libethereum/Dagger.cpp +++ b/libethereum/Dagger.cpp @@ -14,7 +14,7 @@ using namespace std::chrono; namespace eth { -Dagger::Dagger(h256 _hash): m_hash(_hash) +Dagger::Dagger() { } @@ -22,30 +22,45 @@ Dagger::~Dagger() { } -u256 Dagger::bound(u256 _diff) +u256 Dagger::bound(u256 const& _difficulty) { - return (u256)((bigint(1) << 256) / _diff); + return (u256)((bigint(1) << 256) / _difficulty); } -u256 Dagger::search(uint _msTimeout, u256 _diff) +bool Dagger::verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty) { - static mt19937_64 s_engine((std::random_device())()); - u256 b = bound(_diff); + return eval(_root, _nonce) < bound(_difficulty); +} - auto start = steady_clock::now(); +bool Dagger::mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout) +{ + // restart search if root has changed + if (m_root != _root) + { + m_root = _root; + m_nonce = 0; + } - while (steady_clock::now() - start < milliseconds(_msTimeout)) - for (uint sp = std::uniform_int_distribution()(s_engine), j = 0; j < 1000; ++j, ++sp) - if (eval(sp) < b) - return sp; - return 0; + // compute bound + u256 const b = bound(_difficulty); + + // evaluate until we run out of time + for (auto startTime = steady_clock::now(); (steady_clock::now() - startTime) < milliseconds(_msTimeout); m_nonce += 1) + { + if (eval(_root, m_nonce) < b) + { + o_solution = m_nonce; + return true; + } + } + return false; } -template -inline void update(_T& _sha, _U const& _value) +template +inline void update(_T& _sha, u256 const& _value) { int i = 0; - for (_U v = _value; v; ++i, v >>= 8) {} + for (u256 v = _value; v; ++i, v >>= 8) {} byte buf[32]; bytesRef bufRef(buf, i); toBigEndian(_value, bufRef); @@ -53,48 +68,57 @@ inline void update(_T& _sha, _U const& _value) } template -inline u256 get(_T& _sha) +inline void update(_T& _sha, h256 const& _value) { - byte buf[32]; - _sha.TruncatedFinal(buf, 32); - return fromBigEndian(bytesConstRef(buf, 32)); + int i = 0; + byte const* data = _value.data(); + for (; i != 32 && data[i] == 0; ++i); + _sha.Update(data + i, 32 - i); +} + +template +inline h256 get(_T& _sha) +{ + h256 ret; + _sha.TruncatedFinal(&ret[0], 32); + return ret; } -u256 Dagger::node(uint_fast32_t _L, uint_fast32_t _i) const +h256 Dagger::node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i) { if (_L == _i) - return m_hash; + return _root; u256 m = (_L == 9) ? 16 : 3; CryptoPP::SHA3_256 bsha; for (uint_fast32_t k = 0; k < m; ++k) { CryptoPP::SHA3_256 sha; - update(sha, m_hash); - update(sha, m_xn); + 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)get(sha) & ((1 << ((_L - 1) * 3)) - 1); - auto u = node(_L - 1, pk); + 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); } return get(bsha); } -u256 Dagger::eval(u256 _N) +h256 Dagger::eval(h256 const& _root, u256 const& _nonce) { - m_xn = _N >> 26; // with xn = floor(n / 2^26) -> assuming this is with xn = floor(N / 2^26) + h256 extranonce = _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) { //sha256(D || xn || i || k) -> sha256(D || xn || k) - there's no 'i' here! CryptoPP::SHA3_256 sha; - update(sha, m_hash); - update(sha, m_xn); - update(sha, _N); + update(sha, _root); + update(sha, extranonce); + update(sha, _nonce); update(sha, (u256)k); - uint_fast32_t pk = (uint_fast32_t)get(sha) & 0x1ffffff; // mod 8^8 * 2 [ == mod 2^25 ?! ] [ == & ((1 << 25) - 1) ] [ == & 0x1ffffff ] - auto u = node(9, pk); + 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); } return get(bsha); diff --git a/libethereum/Dagger.h b/libethereum/Dagger.h index 89519e1ad..95e8059d0 100644 --- a/libethereum/Dagger.h +++ b/libethereum/Dagger.h @@ -9,18 +9,21 @@ namespace eth class Dagger { public: - Dagger(h256 _hash); + Dagger(); ~Dagger(); - u256 node(uint_fast32_t _L, uint_fast32_t _i) const; - u256 eval(u256 _N); - u256 search(uint _msTimeout, u256 _diff); + static u256 bound(u256 const& _difficulty); + static h256 eval(h256 const& _root, u256 const& _nonce); + static bool verify(h256 const& _root, u256 const& _nonce, u256 const& _difficulty); - static u256 bound(u256 _diff); + bool mine(u256& o_solution, h256 const& _root, u256 const& _difficulty, uint _msTimeout = 100); private: - u256 m_hash; - u256 m_xn; + + static h256 node(h256 const& _root, h256 const& _xn, uint_fast32_t _L, uint_fast32_t _i); + + h256 m_root; + u256 m_nonce; }; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f7e0dd592..3f042b4a5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -250,10 +250,7 @@ bool State::mine(uint _msTimeout) m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock); // TODO: Miner class that keeps dagger between mine calls (or just non-polling mining). - - Dagger d(m_currentBlock.headerHashWithoutNonce()); - m_currentBlock.nonce = d.search(_msTimeout, m_currentBlock.difficulty); - if (m_currentBlock.nonce) + if (m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout)) { // Got it! Compile block: RLPStream ret; diff --git a/libethereum/State.h b/libethereum/State.h index 9ed967c4e..c52c950e6 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -176,6 +176,8 @@ private: Address m_ourAddress; ///< Our address (i.e. the address to which fees go). + Dagger m_dagger; + /// The fee structure. Values yet to be agreed on... static const u256 c_stepFee; static const u256 c_dataFee; diff --git a/test/main.cpp b/test/main.cpp index 0613bd274..6152f2d77 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -39,22 +39,23 @@ int main() /* // Test dagger { - Dagger d((h256)0); + Dagger d; auto s = steady_clock::now(); - cout << hex << d.eval(0); + cout << hex << d.eval((h256)1, 0); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - cout << hex << d.eval(1); + cout << hex << d.eval((h256)1, 1); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; } { - Dagger d((h256)1); + Dagger d; auto s = steady_clock::now(); - cout << hex << d.eval(0); + cout << hex << d.eval((h256)1, 0); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - cout << hex << d.eval(1); + cout << hex << d.eval((h256)1, 1); cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; } - */ + //*/ + /* // Test transaction. bytes tx = fromUserHex("88005401010101010101010101010101010101010101011f0de0b6b3a76400001ce8d4a5100080181c373130a009ba1f10285d4e659568bfcfec85067855c5a3c150100815dad4ef98fd37cf0593828c89db94bd6c64e210a32ef8956eaa81ea9307194996a3b879441f5d");