From 9ae950d4ad42a2610887f3738b8d21cf953e278d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 01/22] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,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.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 212d4333701e51b497d1850ad82fd60da5ae6f4a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 02/22] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 67058a473..1e724c7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1702,7 +1702,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From 5660a17ffed4e052ade82bfd04a5fffa1971f752 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 03/22] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } + static std::string platformInfo(); + static void listDevices() {} + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } + +protected: + void kickOff() override + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } - static std::string platformInfo(); - static void listDevices() {} - static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From 4302afdf2cbeade79409c29d08aa4961e2bee7d3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 04/22] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 271f3ed65..a75b612c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -432,33 +432,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index e6360317f..fc8611ad7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,15 +21,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From 68b2c8ecbf351fde25a02fb0e2f07844ae209f0f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 05/22] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a75b612c5..421dd1bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 1e724c7e6..8bbec9f00 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fc8611ad7..b9f477385 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -25,12 +25,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 6aede0c16..ed022fb75 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// 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 ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// 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::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From 487349bf099873b28578055358f1c86619ef0711 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 06/22] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index ed022fb75..2141c4587 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9f806347e..be44ea009 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1187,7 +1187,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From 7962a50a39ff48c1f435b5c8399d0fb748c3ae41 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 07/22] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From 659858f6c0045f76507916b8d5d06fe84663eab2 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 08/22] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From 0431a97ecbf3588bbefa9c6c651658dfb0bc0636 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 09/22] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 421dd1bb7..271f3ed65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -434,31 +434,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index b9f477385..0e19ac84d 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,10 +21,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 907ea3c8002545e4a9ccdee0f6d588dcbd2e9f85 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 10/22] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From 9d8f9e3517f8e96ad10286a8ba7cf773e04bf39a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 11/22] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 8bbec9f00..4a8501a97 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1311,7 +1311,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// 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::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } From a04ba152e54ace6c46a2bd5043a318d776d55403 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 6 Jul 2015 18:59:19 -0700 Subject: [PATCH 12/22] Modularise nonce, mix hash and seed hash. --- alethzero/MainWin.cpp | 4 +-- ethminer/MinerAux.h | 10 +++---- exp/main.cpp | 2 +- libethcore/BlockInfo.cpp | 45 +++++++++++++----------------- libethcore/BlockInfo.h | 26 +++++++++--------- libethcore/Common.cpp | 5 ++-- libethcore/Common.h | 1 + libethcore/Ethash.cpp | 52 ++++++++++++++++++++++++++++------- libethcore/Ethash.h | 16 +++++++++-- libethcore/EthashAux.cpp | 7 ++++- libethcore/EthashAux.h | 2 +- libethcore/ProofOfWork.h | 1 - libethereum/BlockChain.cpp | 8 +++--- libethereum/BlockQueue.cpp | 12 ++++---- libethereum/State.cpp | 8 +++--- libethereum/State.h | 4 +-- libweb3jsonrpc/JsonHelper.cpp | 7 +++-- mix/MixClient.cpp | 1 - test/TestHelper.cpp | 2 +- 19 files changed, 128 insertions(+), 85 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index e48b58283..4655240e3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1718,7 +1718,7 @@ void Main::on_blocks_currentItemChanged() s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutNonce) << "" << "
"; + s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; s << "
Difficulty: " << info.difficulty << "" << "
"; if (info.number) { @@ -1749,7 +1749,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; - s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << "" << ""; + s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; s << line << "Difficulty: " << uncle.difficulty << "" << ""; auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index ff28132b1..5c6112743 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -254,17 +254,17 @@ public: bi.difficulty = u256(m); auto boundary = bi.boundary(); m = boost::to_lower_copy(string(argv[++i])); - bi.nonce = h64(m); - auto r = EthashAux::eval(seedHash, powHash, bi.nonce); + bi.proof.nonce = h64(m); + auto r = EthashAux::eval(seedHash, powHash, bi.proof.nonce); bool valid = r.value < boundary; cout << (valid ? "VALID :-)" : "INVALID :-(") << endl; cout << r.value << (valid ? " < " : " >= ") << boundary << endl; cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl; - cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl; + cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.proof.nonce << ")" << endl; cout << " with seed as " << seedHash << endl; if (valid) cout << "(mixHash = " << r.mixHash << ")" << endl; - cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.seedHash())->data()) << endl; + cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(bi.proofCache())->data()) << endl; exit(0); } catch (...) @@ -382,7 +382,7 @@ private: { BlockInfo bi; bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl; + cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/exp/main.cpp b/exp/main.cpp index 88608f8cf..9884bd0e1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -197,7 +197,7 @@ int main() bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, bi); + bi.proof = sol; return completed = true; }); f.setWork(bi); diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index fec5b4678..c7acd9091 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -26,7 +26,6 @@ #include #include #include "EthashAux.h" -#include "ProofOfWork.h" #include "Exceptions.h" #include "BlockInfo.h" using namespace std; @@ -57,22 +56,21 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - mixHash = h256(); - nonce = Nonce(); - m_hash = m_seedHash = h256(); + proof = ProofOfWork::Solution(); + m_proofCache = ProofOfWork::HeaderCache(); + m_hash = h256(); } -h256 const& BlockInfo::seedHash() const +ProofOfWork::HeaderCache const& BlockInfo::proofCache() const { - if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); - return m_seedHash; + ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); + return m_proofCache; } h256 const& BlockInfo::hash() const { if (!m_hash) - m_hash = headerHash(WithNonce); + m_hash = headerHash(WithProof); return m_hash; } @@ -90,20 +88,20 @@ BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const return ret; } -h256 BlockInfo::headerHash(IncludeNonce _n) const +h256 BlockInfo::headerHash(IncludeProof _n) const { RLPStream s; streamRLP(s, _n); return sha3(s.out()); } -void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const +void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const { - _s.appendList(_n == WithNonce ? 15 : 13) + _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithNonce) - _s << mixHash << nonce; + if (_n == WithProof) + proof.streamRLP(_s); } h256 BlockInfo::headerHash(bytesConstRef _block) @@ -116,12 +114,12 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); - m_seedHash = h256(); + m_proofCache = ProofOfWork::HeaderCache(); int field = 0; try { - if (_header.itemCount() != 15) + if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); @@ -136,8 +134,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - mixHash = _header[field = 13].toHash(RLP::VeryStrict); - nonce = _header[field = 14].toHash(RLP::VeryStrict); + proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -152,22 +149,18 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ProofOfWork::composeException(ex, *this); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); - ex << errinfo_seedHash(seedHash()); ex << errinfo_target(boundary()); - ex << errinfo_mixHash(mixHash); - Ethash::Result er = EthashAux::eval(seedHash(), headerHash(WithoutNonce), nonce); - ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); BOOST_THROW_EXCEPTION(ex); } else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) { InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutNonce)); - ex << errinfo_nonce(nonce); + ex << errinfo_hash256(headerHash(WithoutProof)); ex << errinfo_difficulty(difficulty); + ProofOfWork::composeExceptionPre(ex, *this); BOOST_THROW_EXCEPTION(ex); } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 79c12ebb4..b77c47c6b 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -24,16 +24,17 @@ #include #include #include "Common.h" +#include "ProofOfWork.h" namespace dev { namespace eth { -enum IncludeNonce +enum IncludeProof { - WithoutNonce = 0, - WithNonce = 1 + WithoutProof = 0, + WithProof = 1 }; enum Strictness @@ -82,8 +83,7 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - h256 mixHash; - Nonce nonce; + typename ProofOfWork::Solution proof; BlockInfo(); explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} @@ -112,14 +112,13 @@ public: gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && extraData == _cmp.extraData && - mixHash == _cmp.mixHash && - nonce == _cmp.nonce; + proof == _cmp.proof; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } void clear(); - void noteDirty() const { m_hash = m_seedHash = m_boundary = h256(); } + void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); @@ -130,16 +129,17 @@ public: u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - h256 const& seedHash() const; + ProofOfWork::HeaderCache const& proofCache() const; h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeNonce _n) const; - void streamRLP(RLPStream& _s, IncludeNonce _n) const; + h256 headerHash(IncludeProof _n) const; + void streamRLP(RLPStream& _s, IncludeProof _n) const; private: - mutable h256 m_seedHash; + + mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; @@ -148,7 +148,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.mixHash << " " << _bi.nonce << " (" << _bi.seedHash() << ")"; + _bi.gasUsed << " " << _bi.timestamp; return _out; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 618703e22..41cd1bba8 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -26,6 +26,7 @@ #include #include "Exceptions.h" #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -112,9 +113,9 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_line = EthReset EthOnMaroon + string(80, ' ') + EthReset; string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; - string const c_space = c_border + string(76, ' ') + c_border; + string const c_space = c_border + string(76, ' ') + c_border + EthReset; stringstream ss; ss << c_line << endl; ss << c_space << endl; diff --git a/libethcore/Common.h b/libethcore/Common.h index 296f0d01d..1e0cdc3b1 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -189,6 +189,7 @@ struct TransactionSkeleton Address to; u256 value; bytes data; + u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; u256 nonce = UndefinedU256; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9be76926d..6a4a1445f 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -46,6 +46,7 @@ #endif #include "BlockInfo.h" #include "EthashAux.h" +#include "Exceptions.h" using namespace std; using namespace std::chrono; @@ -56,6 +57,26 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); +void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +{ + if (!io_out) + io_out = EthashAux::seedHash((unsigned)_h.number); +} + +void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); + _ex << errinfo_mixHash(_bi.proof.mixHash); + _ex << errinfo_seedHash(_bi.proofCache()); + Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); + _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +} + +void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) +{ + _ex << errinfo_nonce(_bi.proof.nonce); +} + std::string Ethash::name() { return "Ethash"; @@ -66,12 +87,23 @@ unsigned Ethash::revision() return ETHASH_REVISION; } +void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) +{ + mixHash = _header[_field].toHash(RLP::VeryStrict); + nonce = _header[++_field].toHash(RLP::VeryStrict); +} + +void Ethash::Solution::streamRLP(RLPStream& io_rlp) const +{ + io_rlp << mixHash << nonce; +} + Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) { WorkPackage ret; ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutNonce); - ret.seedHash = _bi.seedHash(); + ret.headerHash = _bi.headerHash(WithoutProof); + ret.seedHash = _bi.proofCache(); return ret; } @@ -84,7 +116,7 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { - EthashAux::full(_header.seedHash(), true, _f); + EthashAux::full(_header.proofCache(), true, _f); } bool Ethash::preVerify(BlockInfo const& _header) @@ -95,9 +127,9 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), + (uint64_t)(u64)_header.proof.nonce, + (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); return ret; @@ -115,7 +147,7 @@ bool Ethash::verify(BlockInfo const& _header) #endif auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; + bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -125,9 +157,9 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutNonce); - cwarn << "nonce:" << _header.nonce; - cwarn << "mixHash:" << _header.mixHash; + cwarn << "headerHash:" << _header.headerHash(WithoutProof); + cwarn << "nonce:" << _header.proof.nonce; + cwarn << "mixHash:" << _header.proof.mixHash; cwarn << "difficulty:" << _header.difficulty; cwarn << "boundary:" << _header.boundary(); cwarn << "result.value:" << result.value; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 7ffd887d0..5640152f0 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -28,16 +28,20 @@ #include #include #include "Common.h" -#include "BlockInfo.h" #include "Miner.h" class ethash_cl_miner; namespace dev { + +class RLP; +class RLPStream; + namespace eth { +class BlockInfo; class EthashCLHook; class Ethash @@ -45,8 +49,17 @@ class Ethash public: using Miner = GenericMiner; + using HeaderCache = h256; + static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); + static void composeException(Exception& _ex, BlockInfo& _bi); + static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + struct Solution { + bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } + void populateFromRLP(RLP const& io_rlp, int& io_field); + void streamRLP(RLPStream& io_rlp) const; + static const unsigned Fields = 2; Nonce nonce; h256 mixHash; }; @@ -78,7 +91,6 @@ public: static bool verify(BlockInfo const& _header); static bool preVerify(BlockInfo const& _header); static WorkPackage package(BlockInfo const& _header); - static void assignResult(Solution const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } class CPUMiner: public Miner, Worker { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index efb6066f7..db01f3c49 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,6 +200,11 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } +Ethash::Result EthashAux::eval(BlockInfo const& _header) +{ + return eval(_header, _header.proof.nonce); +} + #define DEV_IF_THROWS(X) try { X; } catch (...) unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) @@ -252,7 +257,7 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { - return eval(_header.seedHash(), _header.headerHash(WithoutNonce), _nonce); + return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index d5bd60d44..be07f579c 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -78,7 +78,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } + static Ethash::Result eval(BlockInfo const& _header); static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 764207aef..7b4298047 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -38,7 +38,6 @@ namespace eth * typename Solution * typename CPUMiner * typename GPUMiner - * void assignResult(BlockInfo&, Result) * and a few others. TODO */ using ProofOfWork = Ethash; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 768ed223f..aaafe7ce9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -575,8 +575,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #endif StructuredLogger::chainReceivedNewBlock( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? _block.info.parentHash.abridged() @@ -666,8 +666,8 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _block.info.headerHash(WithoutNonce).abridged(), - _block.info.nonce.abridged(), + _block.info.headerHash(WithoutProof).abridged(), + _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index f95a3880e..690fb60ee 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.hash; + bi.proof.mixHash = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.mixHash == work.hash) + if (it->verified.info.proof.mixHash == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.mixHash == work.hash) + if (i.verified.info.proof.mixHash == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 10d637509..bf55a50ff 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -837,7 +837,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) // Compile block: RLPStream block; block.appendList(3); - m_currentBlock.streamRLP(block, WithNonce); + m_currentBlock.streamRLP(block, WithProof); block.appendRaw(m_currentTxs); block.appendRaw(m_currentUncles); @@ -902,7 +902,7 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithNonce); + ubi.streamRLP(unclesData, WithProof); ++unclesCount; uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) @@ -970,7 +970,7 @@ void State::completeMine() // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithNonce); + m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); @@ -978,7 +978,7 @@ void State::completeMine() cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.nonce.abridged(), + m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() ); diff --git a/libethereum/State.h b/libethereum/State.h index ef8a3251a..0555b6dcd 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -169,11 +169,11 @@ public: if (!m_committedToMine) return false; - PoW::assignResult(_result, m_currentBlock); + m_currentBlock.proof = _result; if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); + cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 96312f625..f7c09ebc2 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -99,11 +99,12 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["gasLimit"] = toJS(_bi.gasLimit); res["timestamp"] = toJS(_bi.timestamp); res["extraData"] = toJS(_bi.extraData); - res["nonce"] = toJS(_bi.nonce); res["logsBloom"] = toJS(_bi.logBloom); - - res["seedHash"] = toJS(_bi.seedHash()); res["target"] = toJS(_bi.boundary()); + + // TODO: move into ProofOfWork. + res["nonce"] = toJS(_bi.proof.nonce); + res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 8373c7c51..ea4686601 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -49,7 +49,6 @@ namespace struct MixPow //dummy POW { typedef int Solution; - static void assignResult(int, BlockInfo const&) {} static bool verify(BlockInfo const&) { return true; } }; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f49ed1e09..b43c4db51 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -81,7 +81,7 @@ void mine(BlockInfo& _bi) bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { - ProofOfWork::assignResult(sol, _bi); + _bi.proof = sol; return completed = true; }); f.setWork(_bi); From 75857ef5d4de3adeeddfc3813ecfc57b267e026f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 13:03:52 -0700 Subject: [PATCH 13/22] Basic Proof-of-Authority sealent. --- eth/main.cpp | 3 + ethminer/MinerAux.h | 28 +++++++-- libdevcrypto/Common.cpp | 5 ++ libdevcrypto/Common.h | 3 + libethcore/Common.cpp | 4 ++ libethcore/Common.h | 13 +++- libethcore/Ethash.cpp | 26 +++++++- libethcore/Ethash.h | 31 +++++++++ libethcore/EthashAux.cpp | 11 ++++ libethcore/EthashAux.h | 1 + libethcore/Farm.h | 1 - libethcore/Miner.h | 11 ---- libethcore/ProofOfWork.cpp | 25 ++++++++ libethcore/ProofOfWork.h | 76 ++++++++++++++++++++++- libethereum/BlockChain.cpp | 4 ++ libethereum/BlockQueue.cpp | 12 ++-- libethereum/Client.cpp | 15 +---- libethereum/Client.h | 2 +- libethereum/State.cpp | 4 +- libethereum/State.h | 2 +- libweb3jsonrpc/JsonHelper.cpp | 2 + libweb3jsonrpc/WebThreeStubServerBase.cpp | 10 ++- 22 files changed, 246 insertions(+), 43 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 67058a473..1e724c7e6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1702,7 +1702,10 @@ int main(int argc, char** argv) { c->setGasPricer(gasPricer); c->setForceMining(forceMining); + // TODO: expose sealant interface. +#if ETH_USING_ETHASH c->setTurboMining(m.minerType() == MinerCLI::MinerType::GPU); +#endif c->setAddress(beneficiary); c->setNetworkId(networkId); } diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 5c6112743..051128669 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -99,10 +99,16 @@ public: Farm }; + +#if ETH_USING_ETHASH MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {} +#else + MinerCLI(OperationMode = OperationMode::None) {} +#endif bool interpretOption(int& i, int argc, char** argv) { +#if ETH_USING_ETHASH string arg = argv[i]; if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { @@ -289,22 +295,29 @@ public: else return false; return true; +#else + (void)i; + (void)argc; + (void)argv; + return false; +#endif } void execute() { +#if ETH_USING_ETHASH if (m_shouldListDevices) { - ProofOfWork::GPUMiner::listDevices(); + Ethash::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); + Ethash::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { #if ETH_ETHASHCL || !ETH_TRUE - if (!ProofOfWork::GPUMiner::configureGPU( + if (!Ethash::GPUMiner::configureGPU( m_localWorkSize, m_globalWorkSizeMultiplier, m_msPerBatch, @@ -315,7 +328,7 @@ public: m_currentBlock )) exit(1); - ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + Ethash::GPUMiner::setNumInstances(m_miningThreads); #else cerr << "Selected GPU mining without having compiled with -DETHASHCL=1" << endl; exit(1); @@ -327,10 +340,12 @@ public: doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); +#endif } static void streamHelp(ostream& _out) { +#if ETH_USING_ETHASH _out #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -367,8 +382,12 @@ public: << " --cl-ms-per-batch Set the OpenCL target milliseconds per batch (global workgroup size). Default is " << toString(ethash_cl_miner::c_defaultMSPerBatch) << ". If 0 is given then no autoadjustment of global work size will happen" << endl #endif ; +#else + (void)_out; +#endif } +#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -576,4 +595,5 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; +#endif }; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 186c6ce06..d64de835c 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -63,6 +63,11 @@ bool dev::SignatureStruct::isValid() const noexcept return true; } +Public SignatureStruct::recover(h256 const& _hash) const +{ + return dev::recover((Signature)*this, _hash); +} + Address dev::ZeroAddress = Address(); Public dev::toPublic(Secret const& _secret) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index c45e060b2..9aeb85a4c 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -54,6 +54,9 @@ struct SignatureStruct /// @returns true if r,s,v values are valid, otherwise false bool isValid() const noexcept; + /// @returns the public part of the key that signed @a _hash to give this sig. + Public recover(h256 const& _hash) const; + h256 r; h256 s; byte v = 0; diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 41cd1bba8..58e506b37 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include "Exceptions.h" #include "ProofOfWork.h" diff --git a/libethcore/Common.h b/libethcore/Common.h index 1e0cdc3b1..1a688fbd8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -192,11 +192,22 @@ struct TransactionSkeleton u256 nonce = UndefinedU256; u256 gas = UndefinedU256; u256 gasPrice = UndefinedU256; - u256 nonce = UndefinedU256; }; void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } +// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast. +/** + * @brief Describes the progress of a mining operation. + */ +struct MiningProgress +{ +// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } + uint64_t hashes = 0; ///< Total number of hashes computed. + uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. + uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 6a4a1445f..c08f26ca9 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -65,16 +65,26 @@ void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) void Ethash::composeException(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); _ex << errinfo_mixHash(_bi.proof.mixHash); _ex << errinfo_seedHash(_bi.proofCache()); Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); +#else + (void)_ex; + (void)_bi; +#endif } void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) { +#if ETH_USING_ETHASH _ex << errinfo_nonce(_bi.proof.nonce); +#else + (void)_ex; + (void)_bi; +#endif } std::string Ethash::name() @@ -103,7 +113,9 @@ Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) WorkPackage ret; ret.boundary = _bi.boundary(); ret.headerHash = _bi.headerHash(WithoutProof); +#if ETH_USING_ETHASH ret.seedHash = _bi.proofCache(); +#endif return ret; } @@ -116,7 +128,12 @@ void Ethash::ensurePrecomputed(unsigned _number) void Ethash::prep(BlockInfo const& _header, std::function const& _f) { +#if ETH_USING_ETHASH EthashAux::full(_header.proofCache(), true, _f); +#else + (void)_header; + (void)_f; +#endif } bool Ethash::preVerify(BlockInfo const& _header) @@ -124,6 +141,7 @@ bool Ethash::preVerify(BlockInfo const& _header) if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) return false; +#if ETH_USING_ETHASH h256 boundary = u256((bigint(1) << 256) / _header.difficulty); bool ret = !!ethash_quick_check_difficulty( @@ -131,8 +149,10 @@ bool Ethash::preVerify(BlockInfo const& _header) (uint64_t)(u64)_header.proof.nonce, (ethash_h256_t const*)_header.proof.mixHash.data(), (ethash_h256_t const*)boundary.data()); - return ret; +#else + return false; +#endif } bool Ethash::verify(BlockInfo const& _header) @@ -146,6 +166,7 @@ bool Ethash::verify(BlockInfo const& _header) } #endif +#if ETH_USING_ETHASH auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; @@ -168,6 +189,9 @@ bool Ethash::verify(BlockInfo const& _header) #endif return slow; +#else + return false; +#endif } unsigned Ethash::CPUMiner::s_numInstances = 0; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 5640152f0..9274e3c72 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -29,6 +29,7 @@ #include #include "Common.h" #include "Miner.h" +#include "Farm.h" class ethash_cl_miner; @@ -162,6 +163,36 @@ public: #else using GPUMiner = CPUMiner; #endif + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; + + struct Farm: public eth::GenericFarm + { + public: + strings sealers() const { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } + + void sealBlock(BlockInfo const& _bi) + { + setWork(_bi); + if (m_opencl) + startGPU(); + else + startCPU(); + + setWork(_bi); + ensurePrecomputed((unsigned)_bi.number); + } + + void disable() { stop(); } + + private: + bool m_opencl = false; + }; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index db01f3c49..42a3cf6fb 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -202,7 +202,12 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing Ethash::Result EthashAux::eval(BlockInfo const& _header) { +#if ETH_USING_ETHASH return eval(_header, _header.proof.nonce); +#else + (void)_header; + return Ethash::Result(); +#endif } #define DEV_IF_THROWS(X) try { X; } catch (...) @@ -257,7 +262,13 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) { +#if ETH_USING_ETHASH return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); +#else + (void)_header; + (void)_nonce; + return Ethash::Result(); +#endif } Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index be07f579c..5ae24898d 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "Ethash.h" diff --git a/libethcore/Farm.h b/libethcore/Farm.h index ba98becca..c43b0fab2 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace dev { diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 415da9878..03eba9880 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,17 +36,6 @@ namespace dev namespace eth { -/** - * @brief Describes the progress of a mining operation. - */ -struct MiningProgress -{ -// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } - uint64_t hashes = 0; ///< Total number of hashes computed. - uint64_t ms = 0; ///< Total number of milliseconds of mining thus far. - uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; } -}; - struct MineInfo: public MiningProgress {}; inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index ec910f7f2..bda1de0af 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -20,5 +20,30 @@ */ #include "ProofOfWork.h" +#include "BlockInfo.h" using namespace std; using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::verify(BlockInfo const& _header) +{ + return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; +} + +bool BasicAuthority::preVerify(BlockInfo const& _header) +{ + return SignatureStruct(_header.proof.sig).isValid(); +} + +BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) +{ + return WorkPackage{_header.headerHash(WithoutProof)}; +} + +void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) +{ + m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); +} + diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7b4298047..0eeed406f 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -23,13 +23,18 @@ #pragma once -#include "Ethash.h" +#include +#include +#include "Common.h" +//#include "Ethash.h" namespace dev { namespace eth { +class BlockInfo; + /** * The proof of work algorithm base type. * @@ -40,7 +45,74 @@ namespace eth * typename GPUMiner * and a few others. TODO */ -using ProofOfWork = Ethash; +class BasicAuthority +{ +public: + struct HeaderCache {}; + static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} + static void composeException(Exception&, BlockInfo&) {} + static void composeExceptionPre(Exception&, BlockInfo&) {} + + struct Solution + { + bool operator==(Solution const& _v) const { return sig == _v.sig; } + void populateFromRLP(RLP const& io_rlp, int& io_field) + { + sig = io_rlp[io_field++].toHash(RLP::VeryStrict); + } + + void streamRLP(RLPStream& io_rlp) const + { + io_rlp << sig; + } + static const unsigned Fields = 1; + Signature sig; + }; + + struct Result + { + Signature sig; + }; + + struct WorkPackage + { + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + }; + + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static void prep(BlockInfo const&, std::function const& = std::function()) {} + static void ensurePrecomputed(unsigned) {} + static bool verify(BlockInfo const& _header); + static bool preVerify(BlockInfo const& _header); + static WorkPackage package(BlockInfo const& _header); + + static const Address Authority; + + struct Farm + { + public: + strings sealers() const { return { "default" }; } + void setSealer(std::string const&) {} + void setSecret(Secret const& _s) { m_secret = _s; } + void sealBlock(BlockInfo const& _bi); + void disable() {} + void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + + private: + Secret m_secret; + std::function m_onSolutionFound; + }; +}; + +using ProofOfWork = BasicAuthority; } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aaafe7ce9..cf7a0905e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -574,6 +574,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } #endif +#if ETH_USING_ETHASH StructuredLogger::chainReceivedNewBlock( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), @@ -581,6 +582,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& "", // TODO: remote id ?? _block.info.parentHash.abridged() ); +#endif // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; h256s route; @@ -665,12 +667,14 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; +#if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), _block.info.parentHash.abridged() ); +#endif } else { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 690fb60ee..b6c548c1f 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,7 +101,7 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.proof.mixHash = work.hash; + bi.sha3Uncles = work.hash; bi.parentHash = work.parentHash; m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.proof.mixHash == work.hash) + if (it->verified.info.sha3Uncles == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,7 +136,7 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.proof.mixHash == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) { // we're next! m_verifying.pop_front(); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.proof.mixHash == work.hash) + if (i.verified.info.sha3Uncles == work.hash) { i = move(res); goto OK; @@ -323,9 +323,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.proof.mixHash)) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.proof.mixHash; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 054cd1c9b..b3495d912 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,7 +325,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.stop(); + m_farm.disable(); { WriteGuard l(x_postMine); @@ -706,19 +706,10 @@ void Client::rejigMining() } if (m_wouldMine) - { - m_farm.setWork(m_miningInfo); - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } + m_farm.sealBlock(m_miningInfo); } if (!m_wouldMine) - m_farm.stop(); + m_farm.disable(); } void Client::noteChanged(h256Hash const& _filters) diff --git a/libethereum/Client.h b/libethereum/Client.h index fac54b010..16672ce45 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - GenericFarm m_farm; ///< Our mining farm. + ProofOfWork::Farm m_farm; ///< Our mining farm. Handler<> m_tqReady; Handler<> m_bqReady; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index bf55a50ff..1656109a9 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -976,12 +976,12 @@ void State::completeMine() ret.swapOut(m_currentBytes); m_currentBlock.noteDirty(); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; - StructuredLogger::minedNewBlock( +/* StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), m_currentBlock.proof.nonce.abridged(), "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - ); + );*/ // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. diff --git a/libethereum/State.h b/libethereum/State.h index 0555b6dcd..f6a8471ea 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -173,7 +173,7 @@ public: if (!PoW::verify(m_currentBlock)) return false; - cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); +// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); completeMine(); diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index f7c09ebc2..7d63ed165 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,9 +102,11 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); +#if ETH_USING_ETHASH // TODO: move into ProofOfWork. res["nonce"] = toJS(_bi.proof.nonce); res["seedHash"] = toJS(_bi.proofCache()); +#endif } return res; } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 166fbb1bb..f2a95f785 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -733,10 +733,12 @@ Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) Json::Value WebThreeStubServerBase::eth_getWork() { Json::Value ret(Json::arrayValue); +#if ETH_USING_ETHASH auto r = client()->getWork(); ret.append(toJS(r.headerHash)); ret.append(toJS(r.seedHash)); ret.append(toJS(r.boundary)); +#endif return ret; } @@ -744,7 +746,13 @@ bool WebThreeStubServerBase::eth_submitWork(string const& _nonce, string const&, { try { - return client()->submitWork(ProofOfWork::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#if ETH_USING_ETHASH + return client()->submitWork(Ethash::Solution{jsToFixed(_nonce), jsToFixed<32>(_mixHash)}); +#else + (void)_nonce; + (void)_mixHash; + return false; +#endif } catch (...) { From db577f831fce7fea9997f1fba57a32a882a6d528 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 9 Jul 2015 20:31:13 -0700 Subject: [PATCH 14/22] libethcore on a new path. --- exp/main.cpp | 41 +++- libethcore/BasicAuthority.cpp | 104 ++++++++++ libethcore/BasicAuthority.h | 91 +++++++++ libethcore/BlockInfo.cpp | 116 +++-------- libethcore/BlockInfo.h | 113 ++++++++--- libethcore/Ethash.cpp | 349 +++++++++++++++++++++++----------- libethcore/Ethash.h | 138 ++++---------- libethcore/Farm.h | 68 ++++--- libethcore/ProofOfWork.cpp | 22 --- libethcore/ProofOfWork.h | 80 +------- libethcore/Sealer.cpp | 26 +++ libethcore/Sealer.h | 58 ++++++ libethereum/BlockChain.cpp | 2 +- libethereum/Client.cpp | 5 +- libethereum/Client.h | 4 +- 15 files changed, 746 insertions(+), 471 deletions(-) create mode 100644 libethcore/BasicAuthority.cpp create mode 100644 libethcore/BasicAuthority.h create mode 100644 libethcore/Sealer.cpp create mode 100644 libethcore/Sealer.h diff --git a/exp/main.cpp b/exp/main.cpp index 9884bd0e1..07eee6a11 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#if 0 #include #include #include @@ -50,7 +51,6 @@ #include #include #include - #include #include #include @@ -65,9 +65,48 @@ using namespace dev::p2p; using namespace dev::shh; namespace js = json_spirit; namespace fs = boost::filesystem; +#else +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; +#endif #if 1 +int main() +{ + BlockInfo bi; + bytes sealedData; + + SealEngineFace* se = BasicAuthority::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); + se->generateSeal(bi); + { + BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.sig(); + } + + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); + { + Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); + cdebug << sealed.nonce(); + } + + return 0; +} + +#elif 0 + int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp new file mode 100644 index 000000000..bbf4e3f2a --- /dev/null +++ b/libethcore/BasicAuthority.cpp @@ -0,0 +1,104 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file BasicAuthority.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Exceptions.h" +#include "BasicAuthority.h" +#include "BlockInfo.h" +using namespace std; +using namespace dev; +using namespace eth; + +const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); + +bool BasicAuthority::BlockHeaderRaw::verify() const +{ + return toAddress(recover(m_sig, hashWithout())) == Authority; +} + +bool BasicAuthority::BlockHeaderRaw::preVerify() const +{ + return SignatureStruct(m_sig).isValid(); +} + +void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) +{ + m_sig = _header[BlockInfo::BasicFields].toHash(); + + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + BOOST_THROW_EXCEPTION(ex); + } +} + + + +class BasicAuthoritySeal: public SealFace +{ +public: + BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + BasicAuthority::BlockHeader h(_bi); + h.m_sig = m_sig; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + Signature m_sig; +}; + +class BasicAuthoritySealEngine: public SealEngineFace +{ +public: + void setSecret(Secret const& _s) { m_secret = _s; } + void generateSeal(BlockInfo const& _bi) + { + BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); + m_onSealGenerated(&s); + } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isMining() const { return false; } + MiningProgress miningProgress() const { return MiningProgress(); } + +private: + Secret m_secret; + std::function m_onSealGenerated; +}; + +SealEngineFace* createSealEngine() +{ + return new BasicAuthoritySealEngine; +} diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h new file mode 100644 index 000000000..616c18340 --- /dev/null +++ b/libethcore/BasicAuthority.h @@ -0,0 +1,91 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file BasicAuthority.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include +#include "BlockInfo.h" +#include "Common.h" +#include "Sealer.h" + +class BasicAuthoritySeal; + +namespace dev +{ +namespace eth +{ + +/** + * The proof of work algorithm base type. + * + * Must implement a basic templated interface, including: + * typename Result + * typename Solution + * typename CPUMiner + * typename GPUMiner + * and a few others. TODO + */ +class BasicAuthority +{ +public: + // TODO: remove + struct Result {}; + struct WorkPackage {}; + static const WorkPackage NullWorkPackage; + + static std::string name() { return "BasicAuthority"; } + static unsigned revision() { return 0; } + static SealEngineFace* createSealEngine(); + + class BlockHeaderRaw: public BlockInfo + { + friend class ::BasicAuthoritySeal; + + public: + bool verify() const; + bool preVerify() const; + + WorkPackage package() const { return NullWorkPackage; } + Signature sig() const { return m_sig; } + + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + static const unsigned SealFields = 1; + + void populateFromHeader(RLP const& _header, Strictness _s); + void streamRLPFields(RLPStream& _s) const { _s << m_sig; } + void clear() { m_sig = Signature(); } + void noteDirty() const {} + + private: + Signature m_sig; + }; + using BlockHeader = BlockHeaderPolished; + + static const Address Authority; +}; + +} +} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index c7acd9091..eb07162fb 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,9 +36,11 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) { - populate(_block, _s, _h); + RLP header = extractHeader(_block); + m_hash = sha3(header.data()); + populateFromHeader(header, _s); } void BlockInfo::clear() @@ -56,22 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - proof = ProofOfWork::Solution(); - m_proofCache = ProofOfWork::HeaderCache(); - m_hash = h256(); -} - -ProofOfWork::HeaderCache const& BlockInfo::proofCache() const -{ - ProofOfWork::ensureHeaderCacheValid(m_proofCache, *this); - return m_proofCache; -} - -h256 const& BlockInfo::hash() const -{ - if (!m_hash) - m_hash = headerHash(WithProof); - return m_hash; + m_hashWithout = h256(); } h256 const& BlockInfo::boundary() const @@ -81,46 +68,48 @@ h256 const& BlockInfo::boundary() const return m_boundary; } -BlockInfo BlockInfo::fromHeader(bytesConstRef _header, Strictness _s, h256 const& _h) +h256 const& BlockInfo::hashWithout() const { - BlockInfo ret; - ret.populateFromHeader(RLP(_header), _s, _h); - return ret; -} - -h256 BlockInfo::headerHash(IncludeProof _n) const -{ - RLPStream s; - streamRLP(s, _n); - return sha3(s.out()); + if (!m_hashWithout) + { + RLPStream s(BasicFields); + streamRLPFields(s); + m_hashWithout = sha3(s.out()); + } + return m_hashWithout; } -void BlockInfo::streamRLP(RLPStream& _s, IncludeProof _n) const +void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s.appendList(_n == WithProof ? 13 + ProofOfWork::Solution::Fields : 13) - << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom + _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom << difficulty << number << gasLimit << gasUsed << timestamp << extraData; - if (_n == WithProof) - proof.streamRLP(_s); } -h256 BlockInfo::headerHash(bytesConstRef _block) +h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) { return sha3(RLP(_block)[0].data()); } -void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) +RLP BlockInfo::extractHeader(bytesConstRef _block) { - m_hash = _h; - if (_h) - assert(_h == dev::sha3(_header.data())); - m_proofCache = ProofOfWork::HeaderCache(); + RLP root(_block); + if (!root.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); + RLP header = root[0]; + if (!header.isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); + if (!root[1].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); + if (!root[2].isList()) + BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); + return header; +} +void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) +{ int field = 0; try { - if (_header.itemCount() != 13 + ProofOfWork::Solution::Fields) - BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); @@ -134,7 +123,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const gasUsed = _header[field = 10].toInt(); timestamp = _header[field = 11].toInt(); extraData = _header[field = 12].toBytes(); - proof.populateFromRLP(_header, field = 13); } catch (Exception const& _e) { @@ -145,25 +133,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) - { - InvalidBlockNonce ex; - ProofOfWork::composeException(ex, *this); - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ex << errinfo_target(boundary()); - BOOST_THROW_EXCEPTION(ex); - } - else if (_s == QuickNonce && parentHash && !ProofOfWork::preVerify(*this)) - { - InvalidBlockNonce ex; - ex << errinfo_hash256(headerHash(WithoutProof)); - ex << errinfo_difficulty(difficulty); - ProofOfWork::composeExceptionPre(ex, *this); - BOOST_THROW_EXCEPTION(ex); - } - if (_s != CheckNothing) { if (gasUsed > gasLimit) @@ -180,24 +149,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } } -void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h) -{ - RLP root(_block); - if (!root.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block needs to be a list") << BadFieldError(0, _block.toString())); - - RLP header = root[0]; - - if (!header.isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block header needs to be a list") << BadFieldError(0, header.data().toString())); - populateFromHeader(header, _s, _h); - - if (!root[1].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block transactions need to be a list") << BadFieldError(1, root[1].data().toString())); - if (!root[2].isList()) - BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); -} - struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; void BlockInfo::verifyInternals(bytesConstRef _block) const @@ -242,9 +193,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::populateFromParent(BlockInfo const& _parent) { - noteDirty(); stateRoot = _parent.stateRoot; - parentHash = _parent.hash(); number = _parent.number + 1; gasLimit = selectGasLimit(_parent); gasUsed = 0; @@ -285,9 +234,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const // Check timestamp is after previous timestamp. if (parentHash) { - if (parentHash != _parent.hash()) - BOOST_THROW_EXCEPTION(InvalidParentHash()); - if (timestamp <= _parent.timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b77c47c6b..cd55bc1f6 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -23,8 +23,9 @@ #include #include +#include #include "Common.h" -#include "ProofOfWork.h" +#include "Exceptions.h" namespace dev { @@ -83,17 +84,12 @@ public: u256 gasUsed; u256 timestamp = Invalid256; bytes extraData; - typename ProofOfWork::Solution proof; BlockInfo(); - explicit BlockInfo(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()): BlockInfo(&_block, _s, _h) {} - explicit BlockInfo(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + BlockInfo(bytesConstRef _block, Strictness _s); - static h256 headerHash(bytes const& _block) { return headerHash(&_block); } - static h256 headerHash(bytesConstRef _block); - - static BlockInfo fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockInfo fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); + static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } + static h256 headerHashFromBlock(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -111,46 +107,113 @@ public: gasLimit == _cmp.gasLimit && gasUsed == _cmp.gasUsed && timestamp == _cmp.timestamp && - extraData == _cmp.extraData && - proof == _cmp.proof; + extraData == _cmp.extraData; } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } - void clear(); - - void noteDirty() const { m_hash = m_boundary = h256(); m_proofCache = ProofOfWork::HeaderCache(); } - - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); - void populate(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } void verifyInternals(bytesConstRef _block) const; void verifyParent(BlockInfo const& _parent) const; void populateFromParent(BlockInfo const& parent); u256 calculateDifficulty(BlockInfo const& _parent) const; u256 selectGasLimit(BlockInfo const& _parent) const; - ProofOfWork::HeaderCache const& proofCache() const; - h256 const& hash() const; h256 const& boundary() const; /// sha3 of the header only. - h256 headerHash(IncludeProof _n) const; - void streamRLP(RLPStream& _s, IncludeProof _n) const; + h256 const& hashWithout() const; + h256 const& hash() const { return m_hash; } -private: +protected: + static RLP extractHeader(bytesConstRef _block); + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); + void streamRLPFields(RLPStream& _s) const; + + void clear(); + void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } + + static const unsigned BasicFields = 13; - mutable ProofOfWork::HeaderCache m_proofCache; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + +private: + mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty }; inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hash() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << + _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp; return _out; } +template +class BlockHeaderPolished: public BlockInfoSub +{ +public: + BlockHeaderPolished() {} + BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} + explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } + explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + + static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + + void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + + void populateFromParent(BlockHeaderPolished const& _parent) + { + noteDirty(); + BlockInfo::parentHash = _parent.hash(); + BlockInfo::populateFromParent(_parent); + } + + void verifyParent(BlockHeaderPolished const& _parent) + { + if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + BOOST_THROW_EXCEPTION(InvalidParentHash()); + BlockInfo::verifyParent(_parent); + } + + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + { + BlockInfo::m_hash = _h; + if (_h) + assert(_h == dev::sha3(_header.data())); + + if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); + + BlockInfo::populateFromHeader(_header, _s); + BlockInfoSub::populateFromHeader(_header, _s); + } + + void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); } + void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); } + + h256 headerHash(IncludeProof _i = WithProof) const + { + RLPStream s; + streamRLP(s, _i); + return sha3(s.out()); + } + + h256 const& hash() const + { + if (!BlockInfo::m_hash) + BlockInfo::m_hash = headerHash(WithProof); + return BlockInfo::m_hash; + } + + void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const + { + _s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0)); + BlockInfo::streamRLPFields(_s); + if (_i == WithProof) + BlockInfoSub::streamRLPFields(_s); + } +}; + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c08f26ca9..c3f19e723 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -47,6 +47,8 @@ #include "BlockInfo.h" #include "EthashAux.h" #include "Exceptions.h" +#include "Farm.h" +#include "Miner.h" using namespace std; using namespace std::chrono; @@ -57,107 +59,58 @@ namespace eth const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); -void Ethash::ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h) +h256 const& Ethash::BlockHeaderRaw::seedHash() const { - if (!io_out) - io_out = EthashAux::seedHash((unsigned)_h.number); + if (!m_seedHash) + m_seedHash = EthashAux::seedHash((unsigned)number); + return m_seedHash; } -void Ethash::composeException(Exception& _ex, BlockInfo& _bi) +void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _s) { -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); - _ex << errinfo_mixHash(_bi.proof.mixHash); - _ex << errinfo_seedHash(_bi.proofCache()); - Ethash::Result er = EthashAux::eval(_bi.proofCache(), _bi.headerHash(WithoutProof), _bi.proof.nonce); - _ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); -#else - (void)_ex; - (void)_bi; -#endif -} - -void Ethash::composeExceptionPre(Exception& _ex, BlockInfo& _bi) -{ -#if ETH_USING_ETHASH - _ex << errinfo_nonce(_bi.proof.nonce); -#else - (void)_ex; - (void)_bi; -#endif -} - -std::string Ethash::name() -{ - return "Ethash"; -} - -unsigned Ethash::revision() -{ - return ETHASH_REVISION; -} + m_mixHash = _header[BlockInfo::BasicFields].toHash(); + m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); -void Ethash::Solution::populateFromRLP(RLP const& _header, int& _field) -{ - mixHash = _header[_field].toHash(RLP::VeryStrict); - nonce = _header[++_field].toHash(RLP::VeryStrict); -} - -void Ethash::Solution::streamRLP(RLPStream& io_rlp) const -{ - io_rlp << mixHash << nonce; -} - -Ethash::WorkPackage Ethash::package(BlockInfo const& _bi) -{ - WorkPackage ret; - ret.boundary = _bi.boundary(); - ret.headerHash = _bi.headerHash(WithoutProof); -#if ETH_USING_ETHASH - ret.seedHash = _bi.proofCache(); -#endif - return ret; -} - -void Ethash::ensurePrecomputed(unsigned _number) -{ - if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) - // 90% of the way to the new epoch - EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); -} - -void Ethash::prep(BlockInfo const& _header, std::function const& _f) -{ -#if ETH_USING_ETHASH - EthashAux::full(_header.proofCache(), true, _f); -#else - (void)_header; - (void)_f; -#endif + // check it hashes according to proof of work or that it's the genesis block. + if (_s == CheckEverything && parentHash && !verify()) + { + InvalidBlockNonce ex; + ex << errinfo_nonce(m_nonce); + ex << errinfo_mixHash(m_mixHash); + ex << errinfo_seedHash(seedHash()); + Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_target(boundary()); + BOOST_THROW_EXCEPTION(ex); + } + else if (_s == QuickNonce && parentHash && !preVerify()) + { + InvalidBlockNonce ex; + ex << errinfo_hash256(hashWithout()); + ex << errinfo_difficulty(difficulty); + ex << errinfo_nonce(m_nonce); + BOOST_THROW_EXCEPTION(ex); + } } -bool Ethash::preVerify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::preVerify() const { - if (_header.number >= ETHASH_EPOCH_LENGTH * 2048) + if (number >= ETHASH_EPOCH_LENGTH * 2048) return false; -#if ETH_USING_ETHASH - h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - bool ret = !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutProof).data(), - (uint64_t)(u64)_header.proof.nonce, - (ethash_h256_t const*)_header.proof.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + (ethash_h256_t const*)hashWithout().data(), + (uint64_t)(u64)m_nonce, + (ethash_h256_t const*)m_mixHash.data(), + (ethash_h256_t const*)boundary().data()); return ret; -#else - return false; -#endif } -bool Ethash::verify(BlockInfo const& _header) +bool Ethash::BlockHeaderRaw::verify() const { - bool pre = preVerify(_header); + bool pre = preVerify(); #if !ETH_DEBUG if (!pre) { @@ -166,9 +119,8 @@ bool Ethash::verify(BlockInfo const& _header) } #endif -#if ETH_USING_ETHASH - auto result = EthashAux::eval(_header); - bool slow = result.value <= _header.boundary() && result.mixHash == _header.proof.mixHash; + auto result = EthashAux::eval(*this); + bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); // cdebug << result.value.hex() << _header.boundary().hex(); @@ -178,25 +130,194 @@ bool Ethash::verify(BlockInfo const& _header) if (!pre && slow) { cwarn << "WARNING: evaluated result gives true whereas ethash_quick_check_difficulty gives false."; - cwarn << "headerHash:" << _header.headerHash(WithoutProof); - cwarn << "nonce:" << _header.proof.nonce; - cwarn << "mixHash:" << _header.proof.mixHash; - cwarn << "difficulty:" << _header.difficulty; - cwarn << "boundary:" << _header.boundary(); + cwarn << "headerHash:" << hashWithout(); + cwarn << "nonce:" << m_nonce; + cwarn << "mixHash:" << m_mixHash; + cwarn << "difficulty:" << difficulty; + cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; } #endif return slow; -#else - return false; +} + +Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const +{ + WorkPackage ret; + ret.boundary = boundary(); + ret.headerHash = hashWithout(); + ret.seedHash = seedHash(); + return ret; +} + +void Ethash::BlockHeaderRaw::prep(std::function const& _f) const +{ + EthashAux::full(seedHash(), true, _f); +} + + + + + + + + +class EthashCPUMiner: public GenericMiner, Worker +{ +public: + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } + static std::string platformInfo(); + static void listDevices() {} + static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } + +protected: + void kickOff() override + { + stopWorking(); + startWorking(); + } + + void pause() override { stopWorking(); } + +private: + void workLoop() override; + static unsigned s_numInstances; +}; + +#if ETH_ETHASHCL || !ETH_TRUE +class EthashGPUMiner: public GenericMiner, Worker +{ + friend class dev::eth::EthashCLHook; + +public: + EthashGPUMiner(ConstructionInfo const& _ci); + ~EthashGPUMiner(); + + static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } + static std::string platformInfo(); + static unsigned getNumDevices(); + static void listDevices(); + static bool configureGPU( + unsigned _localWorkSize, + unsigned _globalWorkSizeMultiplier, + unsigned _msPerBatch, + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); + static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + +protected: + void kickOff() override; + void pause() override; + +private: + void workLoop() override; + bool report(uint64_t _nonce); + + using Miner::accumulateHashes; + + EthashCLHook* m_hook = nullptr; + ethash_cl_miner* m_miner = nullptr; + + h256 m_minerSeed; ///< Last seed in m_miner + static unsigned s_platformId; + static unsigned s_deviceId; + static unsigned s_numInstances; +}; #endif + +class EthashSeal: public SealFace +{ +public: + EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} + + virtual bytes sealedHeader(BlockInfo const& _bi) const + { + Ethash::BlockHeader h(_bi); + h.m_mixHash = m_mixHash; + h.m_nonce = m_nonce; + RLPStream ret; + h.streamRLP(ret); + return ret.out(); + } + +private: + h256 m_mixHash; + h64 m_nonce; +}; + +struct EthashSealEngine: public SealEngineFace +{ +public: + EthashSealEngine() + { + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; +#if ETH_ETHASHCL + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; +#endif + m_farm.setSealers(sealers); + } + + strings sealers() const override { return { "cpu", "opencl" }; } + void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } + void disable() override { m_farm.stop(); } + void generateSeal(BlockInfo const& _bi) override + { + m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_farm.start(m_sealer); + m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + Ethash::ensurePrecomputed((unsigned)_bi.number); + } + void onSealGenerated(std::function const& _f) override + { + m_farm.onSolutionFound([=](Ethash::Solution const& sol) + { + EthashSeal s(sol.mixHash, sol.nonce); + _f(&s); + return true; + }); + } + +private: + bool m_opencl = false; + eth::GenericFarm m_farm; + std::string m_sealer; +}; + +SealEngineFace* Ethash::createSealEngine() +{ + return new EthashSealEngine; +} + +std::string Ethash::name() +{ + return "Ethash"; +} + +unsigned Ethash::revision() +{ + return ETHASH_REVISION; +} + +void Ethash::ensurePrecomputed(unsigned _number) +{ + if (_number % ETHASH_EPOCH_LENGTH > ETHASH_EPOCH_LENGTH * 9 / 10) + // 90% of the way to the new epoch + EthashAux::computeFull(EthashAux::seedHash(_number + ETHASH_EPOCH_LENGTH), true); } -unsigned Ethash::CPUMiner::s_numInstances = 0; +unsigned EthashCPUMiner::s_numInstances = 0; -void Ethash::CPUMiner::workLoop() +void EthashCPUMiner::workLoop() { auto tid = std::this_thread::get_id(); static std::mt19937_64 s_eng((time(0) + std::hash()(tid))); @@ -220,7 +341,7 @@ void Ethash::CPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Solution{(Nonce)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -243,7 +364,7 @@ static string jsonEncode(map const& _m) return ret + "}"; } -std::string Ethash::CPUMiner::platformInfo() +std::string EthashCPUMiner::platformInfo() { string baseline = toString(std::thread::hardware_concurrency()) + "-thread CPU"; #if ETH_CPUID || !ETH_TRUE @@ -362,28 +483,28 @@ private: uint64_t m_last; bool m_abort = false; Notified m_aborted = {true}; - Ethash::GPUMiner* m_owner = nullptr; + EthashGPUMiner* m_owner = nullptr; }; -unsigned Ethash::GPUMiner::s_platformId = 0; -unsigned Ethash::GPUMiner::s_deviceId = 0; -unsigned Ethash::GPUMiner::s_numInstances = 0; +unsigned EthashGPUMiner::s_platformId = 0; +unsigned EthashGPUMiner::s_deviceId = 0; +unsigned EthashGPUMiner::s_numInstances = 0; -Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): +EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("gpuminer" + toString(index())), m_hook(new EthashCLHook(this)) { } -Ethash::GPUMiner::~GPUMiner() +EthashGPUMiner::~EthashGPUMiner() { pause(); delete m_miner; delete m_hook; } -bool Ethash::GPUMiner::report(uint64_t _nonce) +bool EthashGPUMiner::report(uint64_t _nonce) { Nonce n = (Nonce)(u64)_nonce; Result r = EthashAux::eval(work().seedHash, work().headerHash, n); @@ -392,13 +513,13 @@ bool Ethash::GPUMiner::report(uint64_t _nonce) return false; } -void Ethash::GPUMiner::kickOff() +void EthashGPUMiner::kickOff() { m_hook->reset(); startWorking(); } -void Ethash::GPUMiner::workLoop() +void EthashGPUMiner::workLoop() { // take local copy of work since it may end up being overwritten by kickOff/pause. try { @@ -443,28 +564,28 @@ void Ethash::GPUMiner::workLoop() } } -void Ethash::GPUMiner::pause() +void EthashGPUMiner::pause() { m_hook->abort(); stopWorking(); } -std::string Ethash::GPUMiner::platformInfo() +std::string EthashGPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); } -unsigned Ethash::GPUMiner::getNumDevices() +unsigned EthashGPUMiner::getNumDevices() { return ethash_cl_miner::getNumDevices(s_platformId); } -void Ethash::GPUMiner::listDevices() +void EthashGPUMiner::listDevices() { return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU( +bool EthashGPUMiner::configureGPU( unsigned _localWorkSize, unsigned _globalWorkSizeMultiplier, unsigned _msPerBatch, diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9274e3c72..eee0e3881 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -30,6 +30,7 @@ #include "Common.h" #include "Miner.h" #include "Farm.h" +#include "Sealer.h" class ethash_cl_miner; @@ -48,29 +49,23 @@ class EthashCLHook; class Ethash { public: - using Miner = GenericMiner; - - using HeaderCache = h256; - static void ensureHeaderCacheValid(HeaderCache& io_out, BlockInfo const& _h); - static void composeException(Exception& _ex, BlockInfo& _bi); - static void composeExceptionPre(Exception& _ex, BlockInfo& _bi); + static std::string name(); + static unsigned revision(); + static SealEngineFace* createSealEngine(); + // TODO: remove or virtualize struct Solution { - bool operator==(Solution const& _v) const { return nonce == _v.nonce && mixHash == _v.mixHash; } - void populateFromRLP(RLP const& io_rlp, int& io_field); - void streamRLP(RLPStream& io_rlp) const; - static const unsigned Fields = 2; - Nonce nonce; + h64 nonce; h256 mixHash; }; - + // TODO: make private struct Result { h256 value; h256 mixHash; }; - + // TODO: virtualise struct WorkPackage { WorkPackage() = default; @@ -82,117 +77,50 @@ public: h256 headerHash; ///< When h256() means "pause until notified a new work package is available". h256 seedHash; }; - static const WorkPackage NullWorkPackage; - static std::string name(); - static unsigned revision(); - static void prep(BlockInfo const& _header, std::function const& _f = std::function()); - static void ensurePrecomputed(unsigned _number); - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - class CPUMiner: public Miner, Worker + class BlockHeaderRaw: public BlockInfo { - public: - CPUMiner(ConstructionInfo const& _ci): Miner(_ci), Worker("miner" + toString(index())) {} - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } - static std::string platformInfo(); - static void listDevices() {} - static bool configureGPU(unsigned, unsigned, unsigned, unsigned, unsigned, bool, unsigned, uint64_t) { return false; } - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } - protected: - void kickOff() override - { - stopWorking(); - startWorking(); - } + friend class EthashSeal; - void pause() override { stopWorking(); } + public: + bool verify() const; + bool preVerify() const; - private: - void workLoop() override; - static unsigned s_numInstances; - }; + void prep(std::function const& _f = std::function()) const; + WorkPackage package() const; + h256 const& seedHash() const; + h64 const& nonce() const { return m_nonce; } + h256 const& mixHash() const { return m_mixHash; } -#if ETH_ETHASHCL || !ETH_TRUE - class GPUMiner: public Miner, Worker - { - friend class dev::eth::EthashCLHook; + protected: + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - public: - GPUMiner(ConstructionInfo const& _ci); - ~GPUMiner(); - - static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } - static std::string platformInfo(); - static unsigned getNumDevices(); - static void listDevices(); - static bool configureGPU( - unsigned _localWorkSize, - unsigned _globalWorkSizeMultiplier, - unsigned _msPerBatch, - unsigned _platformId, - unsigned _deviceId, - bool _allowCPU, - unsigned _extraGPUMemory, - uint64_t _currentBlock - ); - static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } + static const unsigned SealFields = 2; - protected: - void kickOff() override; - void pause() override; + void populateFromHeader(RLP const& _header, Strictness _s); + void clear() { m_mixHash = h256(); m_nonce = h64(); } + void noteDirty() const { m_seedHash = h256(); } + void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - void workLoop() override; - bool report(uint64_t _nonce); + h64 m_nonce; + h256 m_mixHash; - using Miner::accumulateHashes; + mutable h256 m_seedHash; + mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + }; + using BlockHeader = BlockHeaderPolished; - EthashCLHook* m_hook = nullptr; - ethash_cl_miner* m_miner = nullptr; + // TODO: Move elsewhere (EthashAux?) + static void ensurePrecomputed(unsigned _number); - h256 m_minerSeed; ///< Last seed in m_miner - static unsigned s_platformId; - static unsigned s_deviceId; - static unsigned s_numInstances; - }; -#else - using GPUMiner = CPUMiner; -#endif /// Default value of the local work size. Also known as workgroup size. static const unsigned defaultLocalWorkSize; /// Default value of the global work size as a multiplier of the local work size static const unsigned defaultGlobalWorkSizeMultiplier; /// Default value of the milliseconds per global work size (per batch) static const unsigned defaultMSPerBatch; - - struct Farm: public eth::GenericFarm - { - public: - strings sealers() const { return { "cpu", "opencl" }; } - void setSealer(std::string const& _sealer) { m_opencl = (_sealer == "opencl"); } - - void sealBlock(BlockInfo const& _bi) - { - setWork(_bi); - if (m_opencl) - startGPU(); - else - startCPU(); - - setWork(_bi); - ensurePrecomputed((unsigned)_bi.number); - } - - void disable() { stop(); } - - private: - bool m_opencl = false; - }; }; } diff --git a/libethcore/Farm.h b/libethcore/Farm.h index c43b0fab2..b69f8325a 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -49,17 +49,17 @@ public: using Solution = typename PoW::Solution; using Miner = GenericMiner; + struct SealerDescriptor + { + std::function instances; + std::function create; + }; + ~GenericFarm() { stop(); } - /** - * @brief Sets the current mining mission. - * @param _bi The block (header) we wish to be mining. - */ - void setWork(BlockInfo const& _bi) { setWork(PoW::package(_bi)); } - /** * @brief Sets the current mining mission. * @param _wp The work package we wish to be mining. @@ -76,18 +76,33 @@ public: resetTimer(); } - /** - * @brief (Re)start miners for CPU only. - * @returns true if started properly. - */ - bool startCPU() { return start(); } + void setSealers(std::map const& _sealers) { m_sealers = _sealers; } /** - * @brief (Re)start miners for GPU only. - * @returns true if started properly. + * @brief Start a number of miners. */ - bool startGPU() { return start(); } + bool start(std::string const& _sealer) + { + WriteGuard l(x_minerWork); + cdebug << "start()"; + if (!m_miners.empty() && m_lastSealer == _sealer) + return true; + if (!m_sealers.count(_sealer)) + return false; + m_miners.clear(); + auto ins = m_sealers[_sealer].instances(); + m_miners.reserve(ins); + for (unsigned i = 0; i < ins; ++i) + { + m_miners.push_back(std::shared_ptr(m_sealers[_sealer].create(std::make_pair(this, i)))); + m_miners.back()->setWork(m_work); + } + m_isMining = true; + m_lastSealer = _sealer; + resetTimer(); + return true; + } /** * @brief Stop all mining activities. */ @@ -168,28 +183,6 @@ private: return false; } - /** - * @brief Start a number of miners. - */ - template - bool start() - { - WriteGuard l(x_minerWork); - cdebug << "start()"; - if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) - return true; - m_miners.clear(); - m_miners.reserve(MinerType::instances()); - for (unsigned i = 0; i < MinerType::instances(); ++i) - { - m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i)))); - m_miners.back()->setWork(m_work); - } - m_isMining = true; - resetTimer(); - return true; - } - void resetTimer() { m_lastStart = std::chrono::steady_clock::now(); @@ -206,6 +199,9 @@ private: std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; + + std::map m_sealers; + std::string m_lastSealer; }; } diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index bda1de0af..843db72c7 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -25,25 +25,3 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); - -bool BasicAuthority::verify(BlockInfo const& _header) -{ - return toAddress(recover(_header.proof.sig, _header.headerHash(WithoutProof))) == Authority; -} - -bool BasicAuthority::preVerify(BlockInfo const& _header) -{ - return SignatureStruct(_header.proof.sig).isValid(); -} - -BasicAuthority::WorkPackage BasicAuthority::package(BlockInfo const& _header) -{ - return WorkPackage{_header.headerHash(WithoutProof)}; -} - -void BasicAuthority::Farm::sealBlock(BlockInfo const& _bi) -{ - m_onSolutionFound(Solution{sign(m_secret, _bi.headerHash(WithoutProof))}); -} - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 0eeed406f..f55c54df6 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -27,91 +27,13 @@ #include #include "Common.h" //#include "Ethash.h" +#include "BasicAuthority.h" namespace dev { namespace eth { -class BlockInfo; - -/** - * The proof of work algorithm base type. - * - * Must implement a basic templated interface, including: - * typename Result - * typename Solution - * typename CPUMiner - * typename GPUMiner - * and a few others. TODO - */ -class BasicAuthority -{ -public: - struct HeaderCache {}; - static void ensureHeaderCacheValid(HeaderCache&, BlockInfo const&) {} - static void composeException(Exception&, BlockInfo&) {} - static void composeExceptionPre(Exception&, BlockInfo&) {} - - struct Solution - { - bool operator==(Solution const& _v) const { return sig == _v.sig; } - void populateFromRLP(RLP const& io_rlp, int& io_field) - { - sig = io_rlp[io_field++].toHash(RLP::VeryStrict); - } - - void streamRLP(RLPStream& io_rlp) const - { - io_rlp << sig; - } - static const unsigned Fields = 1; - Signature sig; - }; - - struct Result - { - Signature sig; - }; - - struct WorkPackage - { - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } - - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - }; - - static const WorkPackage NullWorkPackage; - - static std::string name() { return "BasicAuthority"; } - static unsigned revision() { return 0; } - static void prep(BlockInfo const&, std::function const& = std::function()) {} - static void ensurePrecomputed(unsigned) {} - static bool verify(BlockInfo const& _header); - static bool preVerify(BlockInfo const& _header); - static WorkPackage package(BlockInfo const& _header); - - static const Address Authority; - - struct Farm - { - public: - strings sealers() const { return { "default" }; } - void setSealer(std::string const&) {} - void setSecret(Secret const& _s) { m_secret = _s; } - void sealBlock(BlockInfo const& _bi); - void disable() {} - void onSolutionFound(std::function const& _f) { m_onSolutionFound = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } - - private: - Secret m_secret; - std::function m_onSolutionFound; - }; -}; - using ProofOfWork = BasicAuthority; } diff --git a/libethcore/Sealer.cpp b/libethcore/Sealer.cpp new file mode 100644 index 000000000..9e6f3df4d --- /dev/null +++ b/libethcore/Sealer.cpp @@ -0,0 +1,26 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Sealer.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Sealer.h" +using namespace std; +using namespace dev; +using namespace eth; + diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h new file mode 100644 index 000000000..f491240f3 --- /dev/null +++ b/libethcore/Sealer.h @@ -0,0 +1,58 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Sealer.h + * @author Gav Wood + * @date 2014 + * + * Determines the PoW algorithm. + */ + +#pragma once + +#include +#include "Common.h" + +namespace dev +{ +namespace eth +{ + +class BlockInfo; + +class SealFace +{ +public: + virtual bool wouldSealHeader(BlockInfo const&) const { return true; } + virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; +}; + +class SealEngineFace +{ +public: + virtual strings sealers() const { return { "default" }; } + virtual void setSealer(std::string const&) {} + virtual void generateSeal(BlockInfo const& _bi) = 0; + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void disable() {} + + // TODO: rename & generalise + virtual bool isMining() const { return false; } + virtual MiningProgress miningProgress() const { return MiningProgress(); } +}; + +} +} diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index cf7a0905e..14b13b90d 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -288,7 +288,7 @@ void BlockChain::rebuild(std::string const& _path, std::function +#include #include #include #if ETH_JSONRPC || !ETH_TRUE @@ -31,6 +32,7 @@ #include #include #include +#include #if ETH_JSONRPC || !ETH_TRUE #include "Sentinel.h" #endif @@ -98,7 +100,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_farm.onSolutionFound([=](ProofOfWork::Solution const& s){ return this->submitWork(s); }); + m_sealEngine = shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); m_gp->update(m_bc); diff --git a/libethereum/Client.h b/libethereum/Client.h index 16672ce45..9ae7c7e09 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -36,8 +36,8 @@ #include #include #include +#include #include -#include #include #include "CanonBlockChain.h" #include "TransactionQueue.h" @@ -310,7 +310,7 @@ private: std::weak_ptr m_host; ///< Our Ethereum Host. Don't do anything if we can't lock. - ProofOfWork::Farm m_farm; ///< Our mining farm. + std::shared_ptr m_sealEngine; ///< Our block-sealing engine. Handler<> m_tqReady; Handler<> m_bqReady; From bcce3cb72b58ff6c308005b6d83dbf6bf859d1a9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 10 Jul 2015 16:32:04 -0700 Subject: [PATCH 15/22] Tests working for BasicAuthority and Ethash. --- CMakeLists.txt | 32 ++++++++++++++-------------- exp/CMakeLists.txt | 20 ++++++++++++------ exp/main.cpp | 40 ++++++++++++++++++++++++++--------- libdevcore/Common.h | 1 + libethcore/BasicAuthority.cpp | 18 +++++++++++++--- libethcore/BasicAuthority.h | 7 +++++- libethcore/BlockInfo.h | 2 +- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 1 + libethcore/EthashAux.cpp | 23 -------------------- libethcore/EthashAux.h | 2 -- libethcore/Sealer.h | 12 +++++++++++ 12 files changed, 97 insertions(+), 64 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 271f3ed65..a75b612c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) - add_subdirectory(libweb3jsonrpc) +# add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) - add_subdirectory(libjsengine) - add_subdirectory(libjsconsole) - add_subdirectory(ethconsole) +# add_subdirectory(libjsengine) +# add_subdirectory(libjsconsole) +# add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -432,33 +432,33 @@ endif () add_subdirectory(libethcore) if (GENERAL) - add_subdirectory(libevm) - add_subdirectory(libethereum) - add_subdirectory(libwebthree) +# add_subdirectory(libevm) +# add_subdirectory(libethereum) +# add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) - add_subdirectory(ethminer) +# add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) - add_subdirectory(ethkey) +# add_subdirectory(ethkey) endif () if (TESTS) - add_subdirectory(libtestutils) - add_subdirectory(test) +# add_subdirectory(libtestutils) +# add_subdirectory(test) if (JSONRPC) - add_subdirectory(ethrpctest) +# add_subdirectory(ethrpctest) endif () endif () if (TOOLS) - add_subdirectory(rlp) - add_subdirectory(abi) - add_subdirectory(ethvm) - add_subdirectory(eth) +# add_subdirectory(rlp) +# add_subdirectory(abi) +# add_subdirectory(ethvm) +# add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index e6360317f..fc8611ad7 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,15 +21,21 @@ if (READLINE_FOUND) endif() if (JSONRPC) - target_link_libraries(${EXECUTABLE} web3jsonrpc) +# target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -target_link_libraries(${EXECUTABLE} webthree) -target_link_libraries(${EXECUTABLE} ethereum) -target_link_libraries(${EXECUTABLE} p2p) +#target_link_libraries(${EXECUTABLE} webthree) +#target_link_libraries(${EXECUTABLE} ethereum) +#target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) - target_link_libraries(${EXECUTABLE} ethash-cl) - target_link_libraries(${EXECUTABLE} ethash) - target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} ethash-cl) +# target_link_libraries(${EXECUTABLE} ethash) +# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) endif() +target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) + + + + + diff --git a/exp/main.cpp b/exp/main.cpp index 07eee6a11..fa8603459 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -70,6 +70,7 @@ namespace fs = boost::filesystem; #include #include #include +#include using namespace std; using namespace dev; using namespace eth; @@ -80,24 +81,43 @@ using namespace eth; int main() { BlockInfo bi; + bi.difficulty = c_genesisDifficulty; + bi.gasLimit = c_genesisGasLimit; + bi.number = 1; + bi.parentHash = sha3("parentHash"); + bytes sealedData; - SealEngineFace* se = BasicAuthority::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); }); - se->generateSeal(bi); { + KeyPair kp(sha3("test")); + SealEngineFace* se = BasicAuthority::createSealEngine(); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); + cdebug << se->sealers(); + bool done = false; + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); BasicAuthority::BlockHeader sealed = BasicAuthority::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.sig(); } - SealEngineFace* se = Ethash::createSealEngine(); - cdebug << se->sealers(); - se->onSealGenerated([&](SealFace const* seal){ sealedData = seal->sealedHeader(bi); done = true; }); - se->generateSeal(bi); - while (!done) - this_thread::sleep_for(chrono::milliseconds(50)); { + SealEngineFace* se = Ethash::createSealEngine(); + cdebug << se->sealers(); + bool done = false; + se->setSealer("cpu"); + se->onSealGenerated([&](SealFace const* seal){ + sealedData = seal->sealedHeader(bi); + done = true; + }); + se->generateSeal(bi); + while (!done) + this_thread::sleep_for(chrono::milliseconds(50)); Ethash::BlockHeader sealed = Ethash::BlockHeader::fromHeader(sealedData, CheckEverything); cdebug << sealed.nonce(); } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 303512e57..612b7c685 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -65,6 +65,7 @@ using byte = uint8_t; #define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} #define DEV_IF_NO_ELSE(X) if(!(X)){}else +#define DEV_IF_THROWS(X) try{X;}catch(...) namespace dev { diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index bbf4e3f2a..7006107e1 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -26,11 +26,11 @@ using namespace std; using namespace dev; using namespace eth; -const Address BasicAuthority::Authority = Address("1234567890123456789012345678901234567890"); +AddressHash BasicAuthority::s_authorities; bool BasicAuthority::BlockHeaderRaw::verify() const { - return toAddress(recover(m_sig, hashWithout())) == Authority; + return s_authorities.count(toAddress(recover(m_sig, hashWithout()))); } bool BasicAuthority::BlockHeaderRaw::preVerify() const @@ -94,11 +94,23 @@ public: MiningProgress miningProgress() const { return MiningProgress(); } private: + virtual bool onOptionChanging(std::string const& _name, bytes const& _value) + { + RLP rlp(_value); + if (_name == "authorities") + BasicAuthority::s_authorities = rlp.toUnorderedSet
(); + else if (_name == "authority") + m_secret = rlp.toHash(); + else + return false; + return true; + } + Secret m_secret; std::function m_onSealGenerated; }; -SealEngineFace* createSealEngine() +SealEngineFace* BasicAuthority::createSealEngine() { return new BasicAuthoritySealEngine; } diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 616c18340..9127c1d53 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -30,6 +30,7 @@ #include "Sealer.h" class BasicAuthoritySeal; +class BasicAuthoritySealEngine; namespace dev { @@ -48,6 +49,8 @@ namespace eth */ class BasicAuthority { + friend class ::BasicAuthoritySealEngine; + public: // TODO: remove struct Result {}; @@ -70,6 +73,7 @@ public: Signature sig() const { return m_sig; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 1; @@ -84,7 +88,8 @@ public: }; using BlockHeader = BlockHeaderPolished; - static const Address Authority; +private: + static AddressHash s_authorities; }; } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index cd55bc1f6..710279cb2 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -158,7 +158,7 @@ public: explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(_header, _s, _h); return ret; } + static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index c3f19e723..d385163be 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -119,7 +119,7 @@ bool Ethash::BlockHeaderRaw::verify() const } #endif - auto result = EthashAux::eval(*this); + auto result = EthashAux::eval(seedHash(), hashWithout(), m_nonce); bool slow = result.value <= boundary() && result.mixHash == m_mixHash; // cdebug << (slow ? "VERIFY" : "VERYBAD"); @@ -281,6 +281,7 @@ public: { m_farm.onSolutionFound([=](Ethash::Solution const& sol) { + cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; EthashSeal s(sol.mixHash, sol.nonce); _f(&s); return true; diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index eee0e3881..99baa8a05 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -94,6 +94,7 @@ public: h256 const& mixHash() const { return m_mixHash; } protected: + BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} static const unsigned SealFields = 2; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 42a3cf6fb..00537c21a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -200,18 +200,6 @@ EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing return ret; } -Ethash::Result EthashAux::eval(BlockInfo const& _header) -{ -#if ETH_USING_ETHASH - return eval(_header, _header.proof.nonce); -#else - (void)_header; - return Ethash::Result(); -#endif -} - -#define DEV_IF_THROWS(X) try { X; } catch (...) - unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) { Guard l(get()->x_fulls); @@ -260,17 +248,6 @@ Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonc return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) -{ -#if ETH_USING_ETHASH - return eval(_header.proofCache(), _header.headerHash(WithoutProof), _nonce); -#else - (void)_header; - (void)_nonce; - return Ethash::Result(); -#endif -} - Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 5ae24898d..132b9b436 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -79,8 +79,6 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(BlockInfo const& _header); - static Ethash::Result eval(BlockInfo const& _header, Nonce const& _nonce); static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index f491240f3..28381444e 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -24,6 +24,7 @@ #pragma once #include +#include #include "Common.h" namespace dev @@ -43,6 +44,9 @@ public: class SealEngineFace { public: + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } + bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } + virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; @@ -52,6 +56,14 @@ public: // TODO: rename & generalise virtual bool isMining() const { return false; } virtual MiningProgress miningProgress() const { return MiningProgress(); } + +protected: + virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } + void injectOption(std::string const& _name, bytes const& _value) { Guard l(x_options); m_options[_name] = _value; } + +private: + mutable Mutex x_options; + std::unordered_map m_options; }; } From d16c51a56f922effd5a70afb6c4bd90a10966937 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Wed, 15 Jul 2015 23:24:10 +0200 Subject: [PATCH 16/22] Basic test working with same code for Ethash and BasicAuthority. --- CMakeLists.txt | 4 +- alethzero/MainWin.cpp | 2 +- eth/main.cpp | 1 - ethminer/MinerAux.h | 17 +-- exp/CMakeLists.txt | 6 +- exp/main.cpp | 86 +++++++------ libdevcore/Guards.h | 29 +++++ libdevcore/RLP.h | 3 + libdevcore/TrieDB.h | 9 +- libethcore/BasicAuthority.cpp | 43 ++++--- libethcore/BasicAuthority.h | 16 +-- libethcore/BlockInfo.cpp | 34 +---- libethcore/BlockInfo.h | 64 ++++++--- libethcore/Common.cpp | 3 +- libethcore/Common.h | 14 +- libethcore/Ethash.cpp | 163 ++++++++++++----------- libethcore/Ethash.h | 52 ++------ libethcore/EthashAux.cpp | 17 ++- libethcore/EthashAux.h | 47 ++++++- libethcore/Farm.h | 6 +- libethcore/Miner.h | 4 +- libethcore/ProofOfWork.cpp | 27 ---- libethcore/ProofOfWork.h | 40 ------ libethcore/Sealer.h | 31 +++-- libethereum/BlockChain.cpp | 136 ++++++++++---------- libethereum/BlockChain.h | 113 ++++++++++++++-- libethereum/BlockChainSync.cpp | 11 +- libethereum/BlockQueue.cpp | 24 ++-- libethereum/BlockQueue.h | 8 +- libethereum/CanonBlockChain.cpp | 75 ++++++----- libethereum/CanonBlockChain.h | 45 ++++++- libethereum/Client.cpp | 200 ++++++++++++++++------------- libethereum/Client.h | 119 +++++++++++------ libethereum/ClientBase.cpp | 2 +- libethereum/ClientBase.h | 4 +- libethereum/Interface.h | 8 +- libethereum/State.cpp | 87 ++++++------- libethereum/State.h | 66 ++++------ libethereum/Utility.cpp | 4 +- libethereum/Utility.h | 3 +- libweb3jsonrpc/JsonHelper.cpp | 6 +- libweb3jsonrpc/JsonHelper.h | 14 ++ test/libethcore/dagger.cpp | 3 +- test/libethereum/stateOriginal.cpp | 3 +- 44 files changed, 933 insertions(+), 716 deletions(-) delete mode 100644 libethcore/ProofOfWork.cpp delete mode 100644 libethcore/ProofOfWork.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a75b612c5..421dd1bb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,8 @@ endif () add_subdirectory(libethcore) if (GENERAL) -# add_subdirectory(libevm) -# add_subdirectory(libethereum) + add_subdirectory(libevm) + add_subdirectory(libethereum) # add_subdirectory(libwebthree) endif () diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4655240e3..2ee8928f5 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -208,7 +208,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); diff --git a/eth/main.cpp b/eth/main.cpp index 1e724c7e6..8bbec9f00 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 051128669..61fde605d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #if ETH_ETHASHCL || !ETH_TRUE @@ -387,7 +386,6 @@ public: #endif } -#if ETH_USING_ETHASH enum class MinerType { CPU, @@ -412,10 +410,10 @@ private: genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - GenericFarm f; - f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); + GenericFarm f; + f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; }); - string platformInfo = _m == MinerType::CPU ? ProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? ProofOfWork::GPUMiner::platformInfo() : ""; + string platformInfo = _m == MinerType::CPU ? "CPU" : "GPU";//EthashProofOfWork::CPUMiner::platformInfo() : _m == MinerType::GPU ? EthashProofOfWork::GPUMiner::platformInfo() : ""; cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; @@ -488,20 +486,20 @@ private: jsonrpc::HttpClient client(_remote); Farm rpc(client); - GenericFarm f; + GenericFarm f; if (_m == MinerType::CPU) f.startCPU(); else if (_m == MinerType::GPU) f.startGPU(); - ProofOfWork::WorkPackage current; + EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; while (true) try { bool completed = false; - ProofOfWork::Solution solution; - f.onSolutionFound([&](ProofOfWork::Solution sol) + EthashProofOfWork::Solution solution; + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { solution = sol; return completed = true; @@ -595,5 +593,4 @@ private: string m_farmURL = "http://127.0.0.1:8545"; unsigned m_farmRecheckPeriod = 500; bool m_precompute = true; -#endif }; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index fc8611ad7..b9f477385 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -25,12 +25,12 @@ if (JSONRPC) endif() #target_link_libraries(${EXECUTABLE} webthree) -#target_link_libraries(${EXECUTABLE} ethereum) -#target_link_libraries(${EXECUTABLE} p2p) +target_link_libraries(${EXECUTABLE} ethereum) +target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) # target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash) -# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) +# target_link_libraries(${EXECUTABLE} OpenCL) endif() target_link_libraries(${EXECUTABLE} ethcore) install( TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/exp/main.cpp b/exp/main.cpp index fa8603459..4a35068f1 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -71,13 +70,16 @@ namespace fs = boost::filesystem; #include #include #include +#include +#include +#include +#include using namespace std; using namespace dev; using namespace eth; #endif -#if 1 - +#if 0 int main() { BlockInfo bi; @@ -124,9 +126,7 @@ int main() return 0; } - #elif 0 - int main() { cdebug << pbkdf2("password", asBytes("salt"), 1, 32); @@ -135,10 +135,7 @@ int main() cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); return 0; } - - #elif 0 - int main() { cdebug << "EXP"; @@ -162,9 +159,7 @@ int main() ret = orderedTrieRoot(data); cdebug << ret; } - #elif 0 - int main() { KeyManager keyman; @@ -186,7 +181,6 @@ int main() cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); } - #elif 0 int main() { @@ -246,15 +240,15 @@ int main() #elif 0 int main() { - GenericFarm f; + GenericFarm f; BlockInfo genesis = CanonBlockChain::genesis(); genesis.difficulty = 1 << 18; cdebug << genesis.boundary(); - auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { + auto mine = [](GenericFarm& f, BlockInfo const& g, unsigned timeout) { BlockInfo bi = g; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { bi.proof = sol; return completed = true; @@ -289,23 +283,16 @@ int main() return 0; } -#elif 0 - -void mine(State& s, BlockChain const& _bc) +#elif 1 +void mine(State& s, BlockChain const& _bc, SealEngineFace* _se) { s.commitToMine(_bc); - GenericFarm f; - bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) - { - return completed = s.completeMine(sol); - }); - f.setWork(s.info()); - f.startCPU(); - while (!completed) - this_thread::sleep_for(chrono::milliseconds(20)); + Notified sealed; + _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; }); + _se->generateSeal(s.info()); + sealed.waitNot({}); + s.sealBlock(sealed); } -#elif 0 int main() { cnote << "Testing State..."; @@ -316,47 +303,62 @@ int main() Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; - cout << bc; + using Sealer = Ethash; + CanonBlockChain bc; + auto gbb = bc.headerData(bc.genesisHash()); + assert(Sealer::BlockHeader(bc.headerData(bc.genesisHash()), IgnoreSeal, bc.genesisHash(), HeaderData)); + + SealEngineFace* se = Sealer::createSealEngine(); + KeyPair kp(sha3("test")); + se->setOption("authority", rlp(kp.secret())); + se->setOption("authorities", rlpList(kp.address())); - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); - cout << s; + OverlayDB stateDB = State::openDB(bc.genesisHash()); + cnote << bc; + + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); + cnote << s; // Sync up - this won't do much until we use the last state. s.sync(bc); - cout << s; + cnote << s; // Mine to get some ether! - mine(s, bc); + mine(s, bc, se); - bc.attemptImport(s.blockData(), stateDB); + bytes minedBlock = s.blockData(); + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + bc.import(minedBlock, stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; + cnote << "Miner now has" << s.balance(myMiner.address()); + s.resetCurrent(); + cnote << "Miner now has" << s.balance(myMiner.address()); // Inject a transaction to transfer funds from miner to me. Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); assert(t.sender() == myMiner.address()); s.execute(bc.lastHashes(), t); - cout << s; + cnote << s; // Mine to get some ether and set in stone. s.commitToMine(bc); s.commitToMine(bc); - mine(s, bc); + mine(s, bc, se); bc.attemptImport(s.blockData(), stateDB); - cout << bc; + cnote << bc; s.sync(bc); - cout << s; + cnote << s; return 0; } diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h index 44d5969e4..135209d23 100644 --- a/libdevcore/Guards.h +++ b/libdevcore/Guards.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include #include @@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex; using SharedMutex = boost::shared_mutex; using Guard = std::lock_guard; +using UniqueGuard = std::unique_lock; using RecursiveGuard = std::lock_guard; using ReadGuard = boost::shared_lock; using UpgradableGuard = boost::upgrade_lock; @@ -74,6 +76,33 @@ private: }; using SpinGuard = std::lock_guard; +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(old); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + void waitNot(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value != _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + + template void wait(std::chrono::duration _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); } + template void wait(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); } + template void waitNot(std::chrono::duration _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); } + template void wait(std::chrono::duration _d, F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + /** @brief Simple block guard. * The expression/block following is guarded though the given mutex. * Usage: diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a94c8ba55..701f4b8e8 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -393,6 +393,9 @@ public: /// Read the byte stream. bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; } + /// Invalidate the object and steal the output byte stream. + bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); } + /// Swap the contents of the output stream out for some other byte array. void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index 55ca81023..05affa677 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -231,8 +231,11 @@ public: } } -protected: - DB* db() const { return m_db; } + /// Get the underlying database. + /// @warning This can be used to bypass the trie code. Don't use these unless you *really* + /// know what you're doing. + DB const* db() const { return m_db; } + DB* db() { return m_db; } private: RLPStream& streamNode(RLPStream& _s, bytes const& _b); @@ -383,6 +386,7 @@ public: using Super::isEmpty; using Super::root; + using Super::db; using Super::leftOvers; using Super::check; @@ -435,6 +439,7 @@ public: using Super::check; using Super::open; using Super::setRoot; + using Super::db; std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 7006107e1..22da67080 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -19,6 +19,7 @@ * @date 2014 */ +#include #include "Exceptions.h" #include "BasicAuthority.h" #include "BlockInfo.h" @@ -60,38 +61,38 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri } } +void BasicAuthority::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} +void BasicAuthority::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; +} -class BasicAuthoritySeal: public SealFace +StringHashMap BasicAuthority::BlockHeaderRaw::jsInfo() const { -public: - BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} + return { { "sig", toJS(m_sig) } }; +} - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - BasicAuthority::BlockHeader h(_bi); - h.m_sig = m_sig; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } -private: - Signature m_sig; -}; -class BasicAuthoritySealEngine: public SealEngineFace +class BasicAuthoritySealEngine: public SealEngineBase { public: void setSecret(Secret const& _s) { m_secret = _s; } void generateSeal(BlockInfo const& _bi) { - BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); - m_onSealGenerated(&s); + BasicAuthority::BlockHeader h(_bi); + h.m_sig = sign(m_secret, _bi.hashWithout()); + RLPStream ret; + h.streamRLP(ret); + m_onSealGenerated(ret.out()); } - void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } - bool isMining() const { return false; } - MiningProgress miningProgress() const { return MiningProgress(); } + void onSealGenerated(std::function const& _f) { m_onSealGenerated = _f; } + bool isWorking() const { return false; } + WorkingProgress workingProgress() const { return WorkingProgress(); } private: virtual bool onOptionChanging(std::string const& _name, bytes const& _value) @@ -107,7 +108,7 @@ private: } Secret m_secret; - std::function m_onSealGenerated; + std::function m_onSealGenerated; }; SealEngineFace* BasicAuthority::createSealEngine() diff --git a/libethcore/BasicAuthority.h b/libethcore/BasicAuthority.h index 9127c1d53..8db47938b 100644 --- a/libethcore/BasicAuthority.h +++ b/libethcore/BasicAuthority.h @@ -52,33 +52,31 @@ class BasicAuthority friend class ::BasicAuthoritySealEngine; public: - // TODO: remove - struct Result {}; - struct WorkPackage {}; - static const WorkPackage NullWorkPackage; - static std::string name() { return "BasicAuthority"; } static unsigned revision() { return 0; } static SealEngineFace* createSealEngine(); class BlockHeaderRaw: public BlockInfo { - friend class ::BasicAuthoritySeal; + friend class ::BasicAuthoritySealEngine; public: + static const unsigned SealFields = 1; + bool verify() const; bool preVerify() const; - WorkPackage package() const { return NullWorkPackage; } Signature sig() const { return m_sig; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 1; - void populateFromHeader(RLP const& _header, Strictness _s); + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); void streamRLPFields(RLPStream& _s) const { _s << m_sig; } void clear() { m_sig = Signature(); } void noteDirty() const {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index eb07162fb..64961bc40 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -36,10 +36,10 @@ BlockInfo::BlockInfo(): timestamp(Invalid256) { } -BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s) +BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt) { - RLP header = extractHeader(_block); - m_hash = sha3(header.data()); + RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block); + m_hash = _hashWith ? _hashWith : sha3(header.data()); populateFromHeader(header, _s); } @@ -58,7 +58,7 @@ void BlockInfo::clear() gasUsed = 0; timestamp = 0; extraData.clear(); - m_hashWithout = h256(); + noteDirty(); } h256 const& BlockInfo::boundary() const @@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) if (number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing) - { - if (gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); - - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); - - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); - - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); - } + if (_s != CheckNothing && gasUsed > gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent) gasLimit = selectGasLimit(_parent); gasUsed = 0; difficulty = calculateDifficulty(_parent); + parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const @@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const void BlockInfo::verifyParent(BlockInfo const& _parent) const { - // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); - - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); - // Check timestamp is after previous timestamp. if (parentHash) { diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 710279cb2..b00fa73fb 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -42,10 +42,18 @@ enum Strictness { CheckEverything, QuickNonce, - IgnoreNonce, + IgnoreSeal, CheckNothing }; +enum BlockDataType +{ + HeaderData, + BlockData +}; + +DEV_SIMPLE_EXCEPTION(NoHashRecorded); + /** @brief Encapsulation of a block header. * Class to contain all of a block header's data. It is able to parse a block header and populate * from some given RLP block serialisation with the static fromHeader(), through the method @@ -69,7 +77,10 @@ enum Strictness */ struct BlockInfo { + friend class BlockChain; public: + static const unsigned BasicFields = 13; + // TODO: make them all private! h256 parentHash; h256 sha3Uncles; @@ -78,7 +89,7 @@ public: h256 transactionsRoot; h256 receiptsRoot; LogBloom logBloom; - u256 difficulty; + u256 difficulty; // TODO: pull out into BlockHeader u256 number; u256 gasLimit; u256 gasUsed; @@ -86,10 +97,12 @@ public: bytes extraData; BlockInfo(); - BlockInfo(bytesConstRef _block, Strictness _s); + explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); + explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); } static h256 headerHashFromBlock(bytesConstRef _block); + static RLP extractHeader(bytesConstRef _block); explicit operator bool() const { return timestamp != Invalid256; } @@ -121,17 +134,14 @@ public: /// sha3 of the header only. h256 const& hashWithout() const; - h256 const& hash() const { return m_hash; } - -protected: - static RLP extractHeader(bytesConstRef _block); - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce); - void streamRLPFields(RLPStream& _s) const; + h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } void clear(); void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } - static const unsigned BasicFields = 13; +protected: + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal); + void streamRLPFields(RLPStream& _s) const; mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. @@ -152,35 +162,50 @@ template class BlockHeaderPolished: public BlockInfoSub { public: + static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields; + BlockHeaderPolished() {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} - explicit BlockHeaderPolished(bytes const& _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(&_block, _s, _h); } - explicit BlockHeaderPolished(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } + explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); } + explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); } - static BlockHeaderPolished fromHeader(bytes const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { return fromHeader(bytesConstRef(&_header), _s, _h); } - static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } + // deprecated - just use constructor instead. + static BlockHeaderPolished fromHeader(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } + static BlockHeaderPolished fromHeader(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { return BlockHeaderPolished(_data, _s, _h, HeaderData); } - void populate(bytesConstRef _block, Strictness _s, h256 const& _h = h256()) { populateFromHeader(BlockInfo::extractHeader(_block), _s, _h); } + // deprecated for public API - use constructor. + // TODO: make private. + void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData) + { + populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h); + } void populateFromParent(BlockHeaderPolished const& _parent) { noteDirty(); BlockInfo::parentHash = _parent.hash(); BlockInfo::populateFromParent(_parent); + BlockInfoSub::populateFromParent(_parent); } + // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); + BlockInfoSub::verifyParent(_parent); } - void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) + // deprecated for public API - use constructor. + // TODO: make private. + void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256()) { BlockInfo::m_hash = _h; if (_h) assert(_h == dev::sha3(_header.data())); + else + BlockInfo::m_hash = dev::sha3(_header.data()); if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); @@ -213,6 +238,13 @@ public: if (_i == WithProof) BlockInfoSub::streamRLPFields(_s); } + + bytes sealFieldsRLP() const + { + RLPStream s; + BlockInfoSub::streamRLPFields(s); + return s.out(); + } }; } diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 58e506b37..499854584 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -29,7 +29,6 @@ #include #include #include "Exceptions.h" -#include "ProofOfWork.h" #include "BlockInfo.h" using namespace std; using namespace dev; @@ -57,7 +56,7 @@ Network const c_network = Network::Frontier; Network const c_network = Network::Olympic; #endif -const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9); +const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9); vector> const& units() { diff --git a/libethcore/Common.h b/libethcore/Common.h index 1a688fbd8..5c0a0cc79 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -124,10 +124,16 @@ struct ImportRequirements using value = unsigned; enum { - ValidNonce = 1, ///< Validate nonce + ValidSeal = 1, ///< Validate seal DontHave = 2, ///< Avoid old blocks - CheckUncles = 4, ///< Check uncle nonces - Default = ValidNonce | DontHave | CheckUncles + UncleBasic = 4, ///< Check the basic structure of the uncles. + TransactionBasic = 8, ///< Check the basic structure of the transactions. + UncleSeals = 16, ///< Check the basic structure of the uncles. + TransactionSignatures = 32, ///< Check the basic structure of the transactions. + CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals + CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures + Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + None = 0 }; }; @@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(& /** * @brief Describes the progress of a mining operation. */ -struct MiningProgress +struct WorkingProgress { // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; } uint64_t hashes = 0; ///< Total number of hashes computed. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index d385163be..128822b80 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include "Exceptions.h" #include "Farm.h" #include "Miner.h" +#include "Params.h" using namespace std; using namespace std::chrono; @@ -57,8 +59,6 @@ namespace dev namespace eth { -const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage(); - h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) @@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); ex << errinfo_mixHash(m_mixHash); ex << errinfo_seedHash(seedHash()); - Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); + EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); ex << errinfo_difficulty(difficulty); @@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } + + if (_s != CheckNothing) + { + if (difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + + if (gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + + if (number && extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + } +} + +void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) +{ + // Check difficulty is correct given the two timestamps. + if (difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + + if (gasLimit < c_minGasLimit || + gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || + gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); +} + +void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) +{ + (void)_parent; } bool Ethash::BlockHeaderRaw::preVerify() const @@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const return slow; } -Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const -{ - WorkPackage ret; - ret.boundary = boundary(); - ret.headerHash = hashWithout(); - ret.seedHash = seedHash(); - return ret; -} - void Ethash::BlockHeaderRaw::prep(std::function const& _f) const { EthashAux::full(seedHash(), true, _f); } +StringHashMap Ethash::BlockHeaderRaw::jsInfo() const +{ + return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } }; +} @@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function const& _f) const -class EthashCPUMiner: public GenericMiner, Worker +class EthashCPUMiner: public GenericMiner, Worker { public: - EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} + EthashCPUMiner(GenericMiner::ConstructionInfo const& _ci): GenericMiner(_ci), Worker("miner" + toString(index())) {} static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); @@ -190,7 +214,7 @@ private: }; #if ETH_ETHASHCL || !ETH_TRUE -class EthashGPUMiner: public GenericMiner, Worker +class EthashGPUMiner: public GenericMiner, Worker { friend class dev::eth::EthashCLHook; @@ -234,66 +258,84 @@ private: }; #endif -class EthashSeal: public SealFace +struct EthashSealEngine: public SealEngineBase { -public: - EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {} - - virtual bytes sealedHeader(BlockInfo const& _bi) const - { - Ethash::BlockHeader h(_bi); - h.m_mixHash = m_mixHash; - h.m_nonce = m_nonce; - RLPStream ret; - h.streamRLP(ret); - return ret.out(); - } - -private: - h256 m_mixHash; - h64 m_nonce; -}; + friend class Ethash; -struct EthashSealEngine: public SealEngineFace -{ public: EthashSealEngine() { - map::SealerDescriptor> sealers; - sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; + map::SealerDescriptor> sealers; + sealers["cpu"] = GenericFarm::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; #if ETH_ETHASHCL - sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; + sealers["opencl"] = GenericFarm::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; #endif m_farm.setSealers(sealers); } - strings sealers() const override { return { "cpu", "opencl" }; } + strings sealers() const override + { + return { + "cpu" +#if ETH_ETHASHCL + , "opencl" +#endif + }; + } void setSealer(std::string const& _sealer) override { m_sealer = _sealer; } - void disable() override { m_farm.stop(); } + void cancelGeneration() override { m_farm.stop(); } void generateSeal(BlockInfo const& _bi) override { - m_farm.setWork(Ethash::BlockHeader(_bi).package()); + m_sealing = Ethash::BlockHeader(_bi); + m_farm.setWork(m_sealing); m_farm.start(m_sealer); - m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after... + m_farm.setWork(m_sealing); // TODO: take out one before or one after... Ethash::ensurePrecomputed((unsigned)_bi.number); } - void onSealGenerated(std::function const& _f) override + void onSealGenerated(std::function const& _f) override { - m_farm.onSolutionFound([=](Ethash::Solution const& sol) + m_farm.onSolutionFound([=](EthashProofOfWork::Solution const& sol) { cdebug << m_farm.work().seedHash << m_farm.work().headerHash << sol.nonce << EthashAux::eval(m_farm.work().seedHash, m_farm.work().headerHash, sol.nonce).value; - EthashSeal s(sol.mixHash, sol.nonce); - _f(&s); + m_sealing.m_mixHash = sol.mixHash; + m_sealing.m_nonce = sol.nonce; + RLPStream ret; + m_sealing.streamRLP(ret); + _f(ret.out()); return true; }); } private: bool m_opencl = false; - eth::GenericFarm m_farm; - std::string m_sealer; + eth::GenericFarm m_farm; + std::string m_sealer = "cpu"; + Ethash::BlockHeader m_sealing; }; +void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + // Go via the farm since the handler function object is stored as a local within the Farm's lambda. + // Has the side effect of stopping local workers, which is good, as long as it only does it for + // valid submissions. + static_cast&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr); +} + +bool Ethash::isWorking(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.isMining(); + return false; +} + +WorkingProgress Ethash::workingProgress(SealEngineFace* _engine) +{ + if (EthashSealEngine* e = dynamic_cast(_engine)) + return e->m_farm.miningProgress(); + return WorkingProgress(); +} + SealEngineFace* Ethash::createSealEngine() { return new EthashSealEngine; @@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop() { ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); h256 value = h256((uint8_t*)ðashReturn.result, h256::ConstructFromPointer); - if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) + if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)ðashReturn.mix_hash, h256::ConstructFromPointer)})) break; if (!(hashCount % 100)) accumulateHashes(100); @@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE -using UniqueGuard = std::unique_lock; - -template -class Notified -{ -public: - Notified() {} - Notified(N const& _v): m_value(_v) {} - Notified(Notified const&) = delete; - Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } - - operator N() const { UniqueGuard l(m_mutex); return m_value; } - - void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } - void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } - template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } - -private: - mutable Mutex m_mutex; - mutable std::condition_variable m_cv; - N m_value; -}; - class EthashCLHook: public ethash_cl_miner::search_hook { public: diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99baa8a05..576621bd4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -53,59 +53,42 @@ public: static unsigned revision(); static SealEngineFace* createSealEngine(); - // TODO: remove or virtualize - struct Solution - { - h64 nonce; - h256 mixHash; - }; - // TODO: make private - struct Result - { - h256 value; - h256 mixHash; - }; - // TODO: virtualise - struct WorkPackage - { - WorkPackage() = default; - - void reset() { headerHash = h256(); } - operator bool() const { return headerHash != h256(); } + using Nonce = h64; - h256 boundary; - h256 headerHash; ///< When h256() means "pause until notified a new work package is available". - h256 seedHash; - }; - static const WorkPackage NullWorkPackage; + static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce); + static bool isWorking(SealEngineFace* _engine); + static WorkingProgress workingProgress(SealEngineFace* _engine); class BlockHeaderRaw: public BlockInfo { - friend class EthashSeal; + friend class EthashSealEngine; public: + static const unsigned SealFields = 2; + bool verify() const; bool preVerify() const; void prep(std::function const& _f = std::function()) const; - WorkPackage package() const; h256 const& seedHash() const; - h64 const& nonce() const { return m_nonce; } + Nonce const& nonce() const { return m_nonce; } h256 const& mixHash() const { return m_mixHash; } + StringHashMap jsInfo() const; + protected: BlockHeaderRaw() = default; BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} - static const unsigned SealFields = 2; - void populateFromHeader(RLP const& _header, Strictness _s); - void clear() { m_mixHash = h256(); m_nonce = h64(); } + void populateFromParent(BlockHeaderRaw const& _parent); + void verifyParent(BlockHeaderRaw const& _parent); + void clear() { m_mixHash = h256(); m_nonce = Nonce(); } void noteDirty() const { m_seedHash = h256(); } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } private: - h64 m_nonce; + Nonce m_nonce; h256 m_mixHash; mutable h256 m_seedHash; @@ -115,13 +98,6 @@ public: // TODO: Move elsewhere (EthashAux?) static void ensurePrecomputed(unsigned _number); - - /// Default value of the local work size. Also known as workgroup size. - static const unsigned defaultLocalWorkSize; - /// Default value of the global work size as a multiplier of the local work size - static const unsigned defaultGlobalWorkSizeMultiplier; - /// Default value of the milliseconds per global work size (per batch) - static const unsigned defaultMSPerBatch; }; } diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 00537c21a..c511978db 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; } EthashAux* dev::eth::EthashAux::s_this = nullptr; +const unsigned EthashProofOfWork::defaultLocalWorkSize = 64; +const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE +const unsigned EthashProofOfWork::defaultMSPerBatch = 0; +const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage(); + EthashAux::~EthashAux() { } @@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing) return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; } -Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const +EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const { ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce); if (!r.success) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; + return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)}; } -Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) +EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { DEV_GUARDED(get()->x_fulls) if (FullType dag = get()->m_fulls[_seedHash].lock()) return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { - return Ethash::Result{ ~h256(), h256() }; + return EthashProofOfWork::Result{ ~h256(), h256() }; } } diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 132b9b436..d42e46d91 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -34,6 +34,47 @@ namespace eth struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; +/// Proof of work definition for Ethash. +struct EthashProofOfWork +{ + struct Solution + { + Nonce nonce; + h256 mixHash; + }; + + struct Result + { + h256 value; + h256 mixHash; + }; + + struct WorkPackage + { + WorkPackage() = default; + WorkPackage(Ethash::BlockHeader const& _bh): + boundary(_bh.boundary()), + headerHash(_bh.hashWithout()), + seedHash(_bh.seedHash()) + {} + void reset() { headerHash = h256(); } + operator bool() const { return headerHash != h256(); } + + h256 boundary; + h256 headerHash; ///< When h256() means "pause until notified a new work package is available". + h256 seedHash; + }; + + static const WorkPackage NullWorkPackage; + + /// Default value of the local work size. Also known as workgroup size. + static const unsigned defaultLocalWorkSize; + /// Default value of the global work size as a multiplier of the local work size + static const unsigned defaultGlobalWorkSizeMultiplier; + /// Default value of the milliseconds per global work size (per batch) + static const unsigned defaultMSPerBatch; +}; + class EthashAux { public: @@ -46,7 +87,7 @@ public: LightAllocation(h256 const& _seedHash); ~LightAllocation(); bytesConstRef data() const; - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; ethash_light_t light; uint64_t size; }; @@ -55,7 +96,7 @@ public: { FullAllocation(ethash_light_t _light, ethash_callback_t _cb); ~FullAllocation(); - Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; + EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; bytesConstRef data() const; uint64_t size() const { return ethash_full_dag_size(full); } ethash_full_t full; @@ -79,7 +120,7 @@ public: /// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false. static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function const& _f = std::function()); - static Ethash::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); + static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce); private: EthashAux() {} diff --git a/libethcore/Farm.h b/libethcore/Farm.h index b69f8325a..c86b4804e 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -123,9 +123,9 @@ public: * @brief Get information on the progress of mining this work package. * @return The progress with mining so far. */ - MiningProgress const& miningProgress() const + WorkingProgress const& miningProgress() const { - MiningProgress p; + WorkingProgress p; p.ms = std::chrono::duration_cast(std::chrono::steady_clock::now() - m_lastStart).count(); { ReadGuard l2(x_minerWork); @@ -195,7 +195,7 @@ private: std::atomic m_isMining = {false}; mutable SharedMutex x_progress; - mutable MiningProgress m_progress; + mutable WorkingProgress m_progress; std::chrono::steady_clock::time_point m_lastStart; SolutionFound m_onSolutionFound; diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 03eba9880..90a5902c4 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -36,9 +36,9 @@ namespace dev namespace eth { -struct MineInfo: public MiningProgress {}; +struct MineInfo: public WorkingProgress {}; -inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p) +inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p) { _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s"; return _out; diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp deleted file mode 100644 index 843db72c7..000000000 --- a/libethcore/ProofOfWork.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProofOfWork.cpp - * @author Gav Wood - * @date 2014 - */ - -#include "ProofOfWork.h" -#include "BlockInfo.h" -using namespace std; -using namespace dev; -using namespace eth; - diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h deleted file mode 100644 index f55c54df6..000000000 --- a/libethcore/ProofOfWork.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - This file is part of cpp-ethereum. - - cpp-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - cpp-ethereum is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with cpp-ethereum. If not, see . -*/ -/** @file ProofOfWork.h - * @author Gav Wood - * @date 2014 - * - * Determines the PoW algorithm. - */ - -#pragma once - -#include -#include -#include "Common.h" -//#include "Ethash.h" -#include "BasicAuthority.h" - -namespace dev -{ -namespace eth -{ - -using ProofOfWork = BasicAuthority; - -} -} diff --git a/libethcore/Sealer.h b/libethcore/Sealer.h index 28381444e..137659dfc 100644 --- a/libethcore/Sealer.h +++ b/libethcore/Sealer.h @@ -25,6 +25,7 @@ #include #include +#include #include "Common.h" namespace dev @@ -34,28 +35,22 @@ namespace eth class BlockInfo; -class SealFace -{ -public: - virtual bool wouldSealHeader(BlockInfo const&) const { return true; } - virtual bytes sealedHeader(BlockInfo const& _bi) const = 0; -}; - class SealEngineFace { public: + virtual std::string name() const = 0; + virtual unsigned revision() const = 0; + virtual unsigned sealFields() const = 0; + virtual bytes sealRLP() const = 0; + bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); } bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; } virtual strings sealers() const { return { "default" }; } virtual void setSealer(std::string const&) {} virtual void generateSeal(BlockInfo const& _bi) = 0; - virtual void onSealGenerated(std::function const& _f) = 0; - virtual void disable() {} - - // TODO: rename & generalise - virtual bool isMining() const { return false; } - virtual MiningProgress miningProgress() const { return MiningProgress(); } + virtual void onSealGenerated(std::function const& _f) = 0; + virtual void cancelGeneration() {} protected: virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } @@ -66,5 +61,15 @@ private: std::unordered_map m_options; }; +template +class SealEngineBase: public SealEngineFace +{ +public: + std::string name() const override { return Sealer::name(); } + unsigned revision() const override { return Sealer::revision(); } + unsigned sealFields() const override { return Sealer::BlockHeader::SealFields; } + bytes sealRLP() const override { RLPStream s(sealFields()); s.appendRaw(typename Sealer::BlockHeader().sealFieldsRLP(), sealFields()); return s.out(); } +}; + } } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 14b13b90d..aae8cbd10 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,12 +35,12 @@ #include #include #include -#include #include #include #include #include "GenesisInfo.h" #include "State.h" +#include "Utility.h" #include "Defaults.h" using namespace std; @@ -48,7 +48,7 @@ using namespace dev; using namespace dev::eth; namespace js = json_spirit; -#define ETH_CATCH 1 +#define ETH_CATCH 0 #define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 @@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32; #endif -BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) +BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p): + m_genesisState(_genesisState) { // initialise deathrow. m_cacheUsage.resize(c_collectionQueueSize); @@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit // Initialise with the genesis as the last block on the longest chain. m_genesisBlock = _genesisBlock; m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); + m_genesisState = _genesisState; + + // remove the next line real soon. we don't need to be supporting this forever. + upgradeDatabase(_path, genesisHash()); if (open(_path, _we) != c_minorProtocolVersion) rebuild(_path, _p); @@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); - BlockInfo bi(b); + BlockInfo bi(&b); if (_prepPoW) - Ethash::prep(bi); + Ethash::ensurePrecomputed((unsigned)bi.number); if (bi.parentHash != lastHash) { @@ -351,7 +356,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; @@ -388,7 +393,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad, _ir); + block = verifyBlock(&_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) @@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& auto parentBlock = block(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; - clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); + clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); @@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(_block, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this); for (unsigned i = 0; i < s.pending().size(); ++i) { @@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db) try { cout << "block..." << flush; - BlockInfo bi = info(h); - cout << "details..." << flush; - BlockDetails bd = details(h); + BlockInfo bi(block(h)); + cout << "extras..." << flush; + details(h); cout << "state..." << flush; if (_db.exists(bi.stateRoot)) break; @@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +bytes BlockChain::headerData(h256 const& _hash) const { - VerifiedBlockRef res; - try - { - Strictness strictness = Strictness::CheckEverything; - if (~_ir & ImportRequirements::ValidNonce) - strictness = Strictness::IgnoreNonce; + if (_hash == m_genesisHash) + return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes(); - res.info.populate(_block, strictness); - res.info.verifyInternals(&_block); - } - catch (Exception& ex) { - ex << errinfo_phase(1); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; + ReadGuard l(x_blocks); + auto it = m_blocks.find(_hash); + if (it != m_blocks.end()) + return BlockInfo::extractHeader(&it->second).data().toBytes(); } - RLP r(_block); - unsigned i = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_uncleIndex(i); - ex << errinfo_now(time(0)); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; - } - i = 0; - for (RLP const& tr: r[1]) + string d; + m_blocksDB->Get(m_readOptions, toSlice(_hash), &d); + + if (d.empty()) { - bytesConstRef d = tr.data(); - try - { - res.transactions.push_back(Transaction(d, CheckTransaction::Everything)); - } - catch (Exception& ex) - { - ex << errinfo_phase(1); - ex << errinfo_transactionIndex(i); - ex << errinfo_transaction(d.toBytes()); - ex << errinfo_block(_block); - if (_onBad) - _onBad(ex); - throw; - } - ++i; + cwarn << "Couldn't find requested block:" << _hash; + return bytes(); } - res.block = bytesConstRef(&_block); - return res; + + noteUsed(_hash); + + WriteGuard l(x_blocks); + m_blocks[_hash].resize(d.size()); + memcpy(m_blocks[_hash].data(), d.data(), d.size()); + + return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes(); } +State BlockChain::genesisState(OverlayDB const& _db) +{ + State ret(_db, BaseState::Empty); + dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it? + ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit. + ret.m_previousBlock = BlockInfo(&m_genesisBlock); + return ret; +} + + + + + + + + + + + + + + + + + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 638c9c3af..50965f2b6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -37,6 +37,7 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" +#include "State.h" namespace std { @@ -86,6 +87,13 @@ enum { }; using ProgressCallback = std::function; +using StateDefinition = std::unordered_map; + +class VersionChecker +{ +public: + VersionChecker(std::string const& _dbPath, h256 const& _genesisHash); +}; /** * @brief Implements the blockchain database. All data this gives is disk-backed. @@ -94,7 +102,7 @@ using ProgressCallback = std::function; class BlockChain { public: - BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); + BlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()); ~BlockChain(); /// Attempt a database re-open. @@ -120,14 +128,17 @@ public: /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; - /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. - BlockInfo info(h256 const& _hash) const { return BlockInfo(block(_hash), IgnoreNonce, _hash); } + /// Get the partial-header of a block (or the most recent mined if none given). Thread-safe. + BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); } BlockInfo info() const { return info(currentHash()); } /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. bytes block(h256 const& _hash) const; bytes block() const { return block(currentHash()); } - bytes oldBlock(h256 const& _hash) const; + + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes headerData(h256 const& _hash) const; + bytes headerData() const { return headerData(currentHash()); } /// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. BlockDetails details(h256 const& _hash) const { return queryExtras(_hash, m_details, x_details, NullBlockDetails); } @@ -264,13 +275,16 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); - /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); - /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } -private: + /// Get a pre-made genesis State object. + State genesisState(OverlayDB const& _db); + + /// Verify block and prepare it for enactment + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const = 0; + +protected: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); @@ -345,6 +359,7 @@ private: /// Genesis block info. h256 m_genesisHash; bytes m_genesisBlock; + std::unordered_map m_genesisState; ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; @@ -354,6 +369,88 @@ private: friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; +template +class FullBlockChain: public BlockChain +{ +public: + using BlockHeader = typename Sealer::BlockHeader; + + FullBlockChain(bytes const& _genesisBlock, StateDefinition const& _genesisState, std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _p = ProgressCallback()): + BlockChain(_genesisBlock, _genesisState, _path, _we, _p) + {} + + /// Get the header of a block (or the most recent mined if none given). Thread-safe. + typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); } + typename Sealer::BlockHeader header() const { return header(currentHash()); } + + virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function const& _onBad, ImportRequirements::value _ir) const override + { + VerifiedBlockRef res; + + try + { + BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); + h.verifyInternals(_block); + h.verifyParent(header(h.parentHash)); + res.info = static_cast(h); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + if (_ir && ImportRequirements::UncleBasic) + for (auto const& uncle: r[2]) + { + try + { + BlockHeader().populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + if (_ir && ImportRequirements::TransactionBasic) + for (RLP const& tr: r[1]) + { + bytesConstRef d = tr.data(); + try + { + res.transactions.push_back(Transaction(d, (_ir & ImportRequirements::TransactionSignatures) ? CheckTransaction::Everything : CheckTransaction::None)); + } + catch (Exception& ex) + { + ex << errinfo_phase(1); + ex << errinfo_transactionIndex(i); + ex << errinfo_transaction(d.toBytes()); + ex << errinfo_block(_block.toBytes()); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + res.block = bytesConstRef(_block); + return res; + } +}; + std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); } diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index 6aede0c16..ed022fb75 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const for (unsigned i = 0; i < itemCount; ++i) { - auto h = BlockInfo::headerHash(_r[i].data()); + auto h = BlockInfo::headerHashFromBlock(_r[i].data()); if (_peer->m_sub.noteBlock(h)) { _peer->addRating(10); - switch (host().bq().import(_r[i].data(), host().chain())) + switch (host().bq().import(_r[i].data())) { case ImportResult::Success: success++; @@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const logNewBlock(h); if (m_state == SyncState::NewBlocks) { - BlockInfo bi; - bi.populateFromHeader(_r[i][0]); + BlockInfo bi(_r[i].data()); if (bi.number > maxUnknownNumber) { maxUnknownNumber = bi.number; @@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP con { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); - auto h = BlockInfo::headerHash(_r[0].data()); + auto h = BlockInfo::headerHashFromBlock(_r[0].data()); if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); else { - switch (host().bq().import(_r[0].data(), host().chain())) + switch (host().bq().import(_r[0].data())) { case ImportResult::Success: _peer->addRating(100); diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index b6c548c1f..6b400b236 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); } catch (...) { @@ -183,11 +183,11 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() } } -ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs) +ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) { clog(BlockQueueTraceChannel) << std::this_thread::get_id(); // Check if we already know this block. - h256 h = BlockInfo::headerHash(_block); + h256 h = BlockInfo::headerHashFromBlock(_block); clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; @@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo return ImportResult::AlreadyKnown; } - // VERIFY: populates from the block and checks the block is internally coherent. BlockInfo bi; - try { - // TODO: quick verify - bi.populate(_block); - bi.verifyInternals(_block); + // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer + // VERIFY: populates from the block and checks the block is internally coherent. + bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info; } catch (Exception const& _e) { @@ -218,7 +216,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; // Check block doesn't already exist first! - if (_bc.isKnown(h)) + if (m_bc->isKnown(h)) { cblockq << "Already known in chain."; return ImportResult::AlreadyInChain; @@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash); + bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else @@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; @@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad) return !m_readySet.empty(); } -void BlockQueue::tick(BlockChain const& _bc) +void BlockQueue::tick() { vector> todo; { @@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc) cblockq << "Importing" << todo.size() << "past-future blocks."; for (auto const& b: todo) - import(&b.second, _bc); + import(&b.second); } template T advanced(T _t, unsigned _n) diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index b9e6f5b3b..97fca7c72 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -76,11 +76,13 @@ public: BlockQueue(); ~BlockQueue(); + void setChain(BlockChain const& _bc) { m_bc = &_bc; } + /// Import a block into the queue. - ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. - void tick(BlockChain const& _bc); + void tick(); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. @@ -138,6 +140,8 @@ private: void updateBad_WITH_LOCK(h256 const& _bad); void drainVerified_WITH_BOTH_LOCKS(); + BlockChain const* m_bc; ///< The blockchain into which our imports go. + mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. h256Hash m_readySet; ///< All blocks ready for chain import. diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index 4e6d89243..eee4b98b7 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -41,14 +40,44 @@ namespace js = json_spirit; #define ETH_CATCH 1 -std::unordered_map const& dev::eth::genesisState() +std::unique_ptr CanonBlockChain::s_genesis; +boost::shared_mutex CanonBlockChain::x_genesis; +Nonce CanonBlockChain::s_nonce(u64(42)); +std::string CanonBlockChain::s_genesisStateJSON; + +CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): + FullBlockChain(createGenesisBlock(), createGenesisState(), _path, _we, _pc) +{ +} + +bytes CanonBlockChain::createGenesisBlock() +{ + RLPStream block(3); + + h256 stateRoot; + { + MemoryDB db; + SecureTrieDB state(&db); + state.init(); + dev::eth::commit(createGenesisState(), state); + stateRoot = state.root(); + } + + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); +} + +unordered_map CanonBlockChain::createGenesisState() { static std::unordered_map s_ret; if (s_ret.empty()) { js::mValue val; - json_spirit::read_string(c_genesisInfo, val); + json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val); for (auto account: val.get_obj()) { u256 balance; @@ -68,53 +97,29 @@ std::unordered_map const& dev::eth::genesisState() return s_ret; } -// TODO: place Registry in here. - -std::unique_ptr CanonBlockChain::s_genesis; -boost::shared_mutex CanonBlockChain::x_genesis; -Nonce CanonBlockChain::s_nonce(u64(42)); - -bytes CanonBlockChain::createGenesisBlock() -{ - RLPStream block(3); - - h256 stateRoot; - { - MemoryDB db; - SecureTrieDB state(&db); - state.init(); - dev::eth::commit(genesisState(), db, state); - stateRoot = state.root(); - } - - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_genesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 << string() << h256() << s_nonce; - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); -} - -CanonBlockChain::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc): - BlockChain(createGenesisBlock(), _path, _we, _pc) +void CanonBlockChain::setGenesisState(std::string const& _json) { + WriteGuard l(x_genesis); + s_genesisStateJSON = _json; + s_genesis.reset(); } -void CanonBlockChain::setGenesisNonce(Nonce const& _n) +void CanonBlockChain::setGenesisNonce(Nonce const& _n) { WriteGuard l(x_genesis); s_nonce = _n; s_genesis.reset(); } -BlockInfo const& CanonBlockChain::genesis() +Ethash::BlockHeader const& CanonBlockChain::genesis() { UpgradableGuard l(x_genesis); if (!s_genesis) { auto gb = createGenesisBlock(); UpgradeGuard ul(l); - s_genesis.reset(new BlockInfo); - s_genesis->populate(&gb); + s_genesis.reset(new Ethash::BlockHeader); + s_genesis->populate(&gb, CheckEverything); } return *s_genesis; } diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index c16479f0d..d79926703 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "BlockDetails.h" #include "Account.h" @@ -45,7 +46,32 @@ std::unordered_map const& genesisState(); * @threadsafe * @todo Make not memory hog (should actually act as a cache and deallocate old entries). */ -class CanonBlockChain: public BlockChain +template +class CanonBlockChain: public FullBlockChain +{ +public: + CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} + CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): + FullBlockChain(createGenesisBlock(), StateDefinition(), _path, _we, _pc) {} + ~CanonBlockChain() {} + + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static bytes createGenesisBlock() + { + RLPStream block(3); + block.appendList(Sealer::BlockHeader::Fields) + << h256() << EmptyListSHA3 << h160() << EmptyTrie << EmptyTrie << EmptyTrie << LogBloom() << 1 << 0 << (u256(1) << 255) << 0 << (unsigned)0 << std::string(); + bytes sealFields = typename Sealer::BlockHeader().sealFieldsRLP(); + block.appendRaw(sealFields, Sealer::BlockHeader::SealFields); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); + } +}; + +template <> +class CanonBlockChain: public FullBlockChain { public: CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} @@ -53,22 +79,35 @@ public: ~CanonBlockChain() {} /// @returns the genesis block header. - static BlockInfo const& genesis(); + static Ethash::BlockHeader const& genesis(); /// @returns the genesis block as its RLP-encoded byte array. /// @note This is slow as it's constructed anew each call. Consider genesis() instead. static bytes createGenesisBlock(); + /// @returns the genesis block as its RLP-encoded byte array. + /// @note This is slow as it's constructed anew each call. Consider genesis() instead. + static std::unordered_map createGenesisState(); + /// Alter the value of the genesis block's nonce. /// @warning Unless you're very careful, make sure you call this right at the start of the /// program, before anything has had the chance to use this class at all. static void setGenesisNonce(Nonce const& _n); + /// Alter all the genesis block's state by giving a JSON string with account details. + /// @TODO implement. + /// @warning Unless you're very careful, make sure you call this right at the start of the + /// program, before anything has had the chance to use this class at all. + static void setGenesisState(std::string const&); + + // TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit, + private: /// Static genesis info and its lock. static boost::shared_mutex x_genesis; - static std::unique_ptr s_genesis; + static std::unique_ptr s_genesis; static Nonce s_nonce; + static std::string s_genesisStateJSON; }; } diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 918480263..ec37302a2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -72,47 +72,43 @@ static const Addresses c_canaries = Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph }; -VersionChecker::VersionChecker(string const& _dbPath) +Client::Client(std::shared_ptr _gp): + Worker("eth", 0), + m_gp(_gp ? _gp : make_shared()) { - upgradeDatabase(_dbPath); } -Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Client(_extNet, make_shared(), _dbPath, _forceAction, _networkId) +void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId) { - startWorking(); -} + // Cannot be opened until after blockchain is open, since BlockChain may upgrade the database. + // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database + // until after the construction. + m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); + m_preMine = State(m_stateDB); + m_postMine = State(m_stateDB); + // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. + m_preMine = bc().genesisState(m_stateDB); -Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth", 0), - m_vc(_dbPath), - m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), - m_gp(_gp), - m_stateDB(State::openDB(_dbPath, _forceAction)), - m_preMine(m_stateDB, BaseState::CanonGenesis), - m_postMine(m_stateDB) -{ - if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + m_bq.setChain(bc()); m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue); m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_sealEngine = shared_ptr(Ethash::createSealEngine()); - m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); }); + bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); - m_gp->update(m_bc); + if (_forceAction == WithExisting::Rescue) + m_bc.rescue(m_stateDB); + + m_gp->update(bc()); - auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId)); + auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId)); m_host = host; _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common if (_dbPath.size()) Defaults::setDBPath(_dbPath); doWork(); - startWorking(); } @@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) { if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000) this_thread::sleep_for(std::chrono::milliseconds(500)); - return m_bq.import(&_block, bc(), _isSafe); + return m_bq.import(&_block, _isSafe); } tuple Client::syncQueue(unsigned _max) { stopWorking(); - return m_bc.sync(m_bq, m_stateDB, _max); + return bc().sync(m_bq, m_stateDB, _max); } void Client::onBadBlock(Exception& _ex) const @@ -294,7 +290,7 @@ void Client::startedWorking() clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -309,7 +305,7 @@ void Client::doneWorking() // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. DEV_WRITE_GUARDED(x_preMine) - m_preMine.sync(m_bc); + m_preMine.sync(bc()); DEV_READ_GUARDED(x_preMine) { DEV_WRITE_GUARDED(x_working) @@ -328,7 +324,7 @@ void Client::killChain() m_tq.clear(); m_bq.clear(); - m_farm.disable(); + m_sealEngine->cancelGeneration(); { WriteGuard l(x_postMine); @@ -340,10 +336,10 @@ void Client::killChain() m_working = State(); m_stateDB = OverlayDB(); - m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); - m_bc.reopen(Defaults::dbPath(), WithExisting::Kill); + m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill); + bc().reopen(Defaults::dbPath(), WithExisting::Kill); - m_preMine = State(m_stateDB, BaseState::CanonGenesis); + m_preMine = bc().genesisState(m_stateDB); m_postMine = State(m_stateDB); } @@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. - auto d = m_bc.info(_block); - auto receipts = m_bc.receipts(_block).receipts; + auto d = bc().info(_block); + auto receipts = bc().receipts(_block).receipts; Guard l(x_filtersWatches); io_changed.insert(ChainChangedFilter); @@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable) startMining(); } -MiningProgress Client::miningProgress() const +bool Client::isMining() const { - if (m_farm.isMining()) - return m_farm.miningProgress(); - return MiningProgress(); + return Ethash::isWorking(m_sealEngine.get()); +} + +WorkingProgress Client::miningProgress() const +{ + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()); + return WorkingProgress(); } uint64_t Client::hashrate() const { - if (m_farm.isMining()) - return m_farm.miningProgress().rate(); + if (Ethash::isWorking(m_sealEngine.get())) + return Ethash::workingProgress(m_sealEngine.get()).rate(); return 0; } @@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 return ret; } -ProofOfWork::WorkPackage Client::getWork() -{ - // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. - // this will be reset as soon as a new block arrives, allowing more transactions to be processed. - bool oldShould = shouldServeWork(); - m_lastGetWork = chrono::system_clock::now(); - - if (!m_mineOnBadChain && isChainBad()) - return ProofOfWork::WorkPackage(); - - // if this request has made us bother to serve work, prep it now. - if (!oldShould && shouldServeWork()) - onPostStateChanged(); - else - // otherwise, set this to true so that it gets prepped next time. - m_remoteWorking = true; - return ProofOfWork::package(m_miningInfo); -} - -bool Client::submitWork(ProofOfWork::Solution const& _solution) -{ - bytes newBlock; - DEV_WRITE_GUARDED(x_working) - if (!m_working.completeMine(_solution)) - return false; - - DEV_READ_GUARDED(x_working) - { - DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; - newBlock = m_working.blockData(); - } - - // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. - m_bq.import(&newBlock, m_bc, true); - - return true; -} - unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; @@ -553,7 +515,7 @@ void Client::syncBlockQueue() ImportRoute ir; unsigned count; Timer t; - tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); if (count) @@ -577,7 +539,7 @@ void Client::syncTransactionQueue() TransactionReceipts newPendingReceipts; DEV_WRITE_GUARDED(x_working) - tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp); + tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp); if (newPendingReceipts.empty()) return; @@ -590,7 +552,7 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). + // Tell farm about new transaction (i.e. restart mining). onPostStateChanged(); // Tell watches about the new transactions. @@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir) for (auto const& h: _ir.deadBlocks) { clog(ClientTrace) << "Dead block:" << h; - for (auto const& t: m_bc.transactions(h)) + for (auto const& t: bc().transactions(h)) { clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None); m_tq.import(t, IfDropped::Retry); @@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir) newPreMine = m_preMine; // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + preChanged = newPreMine.sync(bc()); if (preChanged || m_postMine.address() != m_preMine.address()) { @@ -700,7 +662,7 @@ void Client::rejigMining() { clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) - m_working.commitToMine(m_bc, m_extraData); + m_working.commitToMine(bc(), m_extraData); DEV_READ_GUARDED(x_working) { DEV_WRITE_GUARDED(x_postMine) @@ -709,10 +671,10 @@ void Client::rejigMining() } if (m_wouldMine) - m_farm.sealBlock(m_miningInfo); + m_sealEngine->generateSeal(m_miningInfo); } if (!m_wouldMine) - m_farm.disable(); + m_sealEngine->cancelGeneration(); } void Client::noteChanged(h256Hash const& _filters) @@ -768,7 +730,7 @@ void Client::tick() { m_report.ticks++; checkWatchGarbage(); - m_bq.tick(m_bc); + m_bq.tick(); m_lastTick = chrono::system_clock::now(); if (m_report.ticks == 15) clog(ClientTrace) << activityReport(); @@ -792,7 +754,7 @@ void Client::checkWatchGarbage() uninstallWatch(i); // blockchain GC - m_bc.garbageCollect(); + bc().garbageCollect(); m_lastGarbageCollection = chrono::system_clock::now(); } @@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const try { State ret(m_stateDB); - ret.populateFromChain(m_bc, _block); + ret.populateFromChain(bc(), _block); return ret.fromPending(_txi); } catch (Exception& ex) @@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const try { State ret(m_stateDB); - PopulationStatistics s = ret.populateFromChain(m_bc, _block); + PopulationStatistics s = ret.populateFromChain(bc(), _block); if (o_stats) swap(s, *o_stats); return ret; @@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const auto h = m_host.lock(); return h ? h->status() : SyncStatus(); } + +bool Client::submitSealed(bytes const& _header) +{ + DEV_WRITE_GUARDED(x_working) + if (!m_working.sealBlock(_header)) + return false; + + bytes newBlock; + DEV_READ_GUARDED(x_working) + { + DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; + newBlock = m_working.blockData(); + } + + // OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes. + return m_bq.import(&newBlock, true) == ImportResult::Success; +} + + + + + + + + + + + + + + +std::tuple EthashClient::getEthashWork() +{ + // lock the work so a later submission isn't invalidated by processing a transaction elsewhere. + // this will be reset as soon as a new block arrives, allowing more transactions to be processed. + bool oldShould = shouldServeWork(); + m_lastGetWork = chrono::system_clock::now(); + + if (!m_mineOnBadChain && isChainBad()) + return std::tuple(); + + // if this request has made us bother to serve work, prep it now. + if (!oldShould && shouldServeWork()) + onPostStateChanged(); + else + // otherwise, set this to true so that it gets prepped next time. + m_remoteWorking = true; + Ethash::BlockHeader bh = Ethash::BlockHeader(m_miningInfo); + return std::tuple(bh.boundary(), bh.hashWithout(), bh.seedHash()); +} + +bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce) +{ + Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce); + return true; +} + diff --git a/libethereum/Client.h b/libethereum/Client.h index 9ae7c7e09..73609bd71 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -60,12 +60,6 @@ enum ClientWorkState Deleted }; -class VersionChecker -{ -public: - VersionChecker(std::string const& _dbPath); -}; - struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; }; @@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); /** * @brief Main API hub for interfacing with Ethereum. + * Not to be used directly - subclass. */ class Client: public ClientBase, Worker { public: /// New-style Constructor. - explicit Client( - p2p::Host* _host, - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); - - explicit Client( - p2p::Host* _host, - std::shared_ptr _gpForAdoption, // pass it in with new. - std::string const& _dbPath = std::string(), - WithExisting _forceAction = WithExisting::Trust, - u256 _networkId = 0 - ); + /// Any final derived class's constructor should make sure they call init(). + explicit Client(std::shared_ptr _gpForAdoption); /// Destructor. virtual ~Client(); @@ -129,7 +112,7 @@ public: /// Get the object representing the current state of Ethereum. dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } /// Get the object representing the current canonical blockchain. - CanonBlockChain const& blockChain() const { return m_bc; } + BlockChain const& blockChain() const { return bc(); } /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. @@ -176,26 +159,16 @@ public: /// NOT thread-safe void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? - bool isMining() const override { return m_farm.isMining(); } + bool isMining() const override; /// Are we mining now? bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. - MiningProgress miningProgress() const override; + WorkingProgress miningProgress() const override; /// Get and clear the mining history. std::list miningHistory(); - /// 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 ProofOfWork::WorkPackage getWork() override; - - /** @brief Submit the proof for the proof-of-work. - * @param _s A valid solution. - * @return true if the solution was indeed valid and accepted. - */ - virtual bool submitWork(ProofOfWork::Solution const& _proof) override; - // Debug stuff: DownloadMan const* downloadMan() const; @@ -218,12 +191,20 @@ public: /// Set the extra data that goes into mined blocks. void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } /// Rewind to a prior head. - void rewind(unsigned _n) { m_bc.rewind(_n); } + void rewind(unsigned _n) { bc().rewind(_n); } + /// Rescue the chain. + void rescue() { bc().rescue(m_stateDB); } + /// Get the seal engine. + SealEngineFace* sealEngine() const { return m_sealEngine.get(); } protected: + /// Perform critical setup functions. + /// Must be called in the constructor of the finally derived class. + void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId); + /// InterfaceStub methods - virtual BlockChain& bc() override { return m_bc; } - virtual BlockChain const& bc() const override { return m_bc; } + virtual BlockChain& bc() override = 0; + virtual BlockChain const& bc() const override = 0; /// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Works properly with LatestBlock and PendingBlock. @@ -245,7 +226,10 @@ protected: /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches. void noteChanged(h256Hash const& _filters); -private: + /// Submit + bool submitSealed(bytes const& _s); + +protected: /// Called when Worker is starting. void startedWorking() override; @@ -291,8 +275,6 @@ private: /// @warning May be called from any thread. void onBadBlock(Exception& _ex) const; - VersionChecker m_vc; ///< Dummy object to check & update the protocol version. - CanonBlockChain m_bc; ///< Maintains block database. BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). std::shared_ptr m_gp; ///< The gas pricer. @@ -339,5 +321,64 @@ private: bytes m_extraData; }; +template +class SpecialisedClient: public Client +{ +public: + explicit SpecialisedClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): + Client(_gpForAdoption), + m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ std::cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }) + { + m_sealEngine = std::shared_ptr(Ethash::createSealEngine()); + m_sealEngine->onSealGenerated([=](bytes const& header){ + return this->submitSealed(header); + }); + init(_host, _dbPath, _forceAction, _networkId); + } + + /// Get the object representing the current canonical blockchain. + CanonBlockChain const& blockChain() const { return m_bc; } + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } + +protected: + CanonBlockChain m_bc; ///< Maintains block database. +}; + +class EthashClient: public SpecialisedClient +{ +public: + /// Trivial forwarding constructor. + explicit EthashClient( + p2p::Host* _host, + std::shared_ptr _gpForAdoption, + std::string const& _dbPath = std::string(), + WithExisting _forceAction = WithExisting::Trust, + u256 _networkId = 0 + ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + + /// 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::tuple getEthashWork() override; + + /** @brief Submit the proof for the proof-of-work. + * @param _s A valid solution. + * @return true if the solution was indeed valid and accepted. + */ + virtual bool submitEthashWork(h256 const& _mixHash, h64 const& _nonce) override; + +protected: + virtual BlockChain& bc() override { return m_bc; } + virtual BlockChain const& bc() const override { return m_bc; } +}; + } } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index f463b0195..769880269 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const auto bl = bc().block(_blockHash); RLP b(bl); if (_i < b[2].itemCount()) - return BlockInfo::fromHeader(b[2][_i].data()); + return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData); else return BlockInfo(); } diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 82f03def0..874f10548 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -156,9 +156,7 @@ public: virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } - virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } - virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } - virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); } + virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } State asOf(BlockNumber _h) const; diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 973433af9..213e7fb26 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "LogFilter.h" #include "Transaction.h" #include "AccountDiff.h" @@ -207,12 +207,12 @@ public: virtual uint64_t hashrate() const = 0; /// Get hash of the current block to be mined minus the nonce (the 'work hash'). - virtual ProofOfWork::WorkPackage getWork() = 0; + virtual std::tuple getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); } /// Submit the nonce for the proof-of-work. - virtual bool submitWork(ProofOfWork::Solution const& _proof) = 0; + virtual bool submitEthashWork(h256 const&, h64 const&) { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::submitEthashWork")); } /// Check the progress of the mining. - virtual MiningProgress miningProgress() const = 0; + virtual WorkingProgress miningProgress() const = 0; protected: int m_default = PendingBlock; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1656109a9..ee2078a07 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } -OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) +OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; @@ -65,7 +65,7 @@ OverlayDB State::openDB(std::string const& _basePath, WithExisting _we) boost::filesystem::remove_all(path + "/state"); } - path += "/" + toHex(CanonBlockChain::genesis().hash().ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); + path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); ldb::Options o; @@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): paranoia("beginning of Genesis construction.", true); - if (_bs == BaseState::CanonGenesis) - { - dev::eth::commit(genesisState(), m_db, m_state); - m_db.commit(); - - paranoia("after DB commit of Genesis construction.", true); - m_previousBlock = CanonBlockChain::genesis(); - } - else - m_previousBlock.clear(); - - resetCurrent(); - - assert(m_state.root() == m_previousBlock.stateRoot); + m_previousBlock.clear(); + m_currentBlock.clear(); +// assert(m_state.root() == m_previousBlock.stateRoot); paranoia("end of normal construction.", true); } @@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip; - bip.populate(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip, _ir); + BlockInfo bip(_bc.block(bi.parentHash)); + sync(_bc, bi.parentHash, bip); // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; Timer t; - auto vb = BlockChain::verifyBlock(b); + auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); t.restart(); - enact(vb, _bc, _ir); + enact(vb, _bc); ret.enact = t.elapsed(); } else @@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // Genesis required: // We know there are no transactions, so just populate directly. m_state.init(); - sync(_bc, _h, bi, _ir); + sync(_bc, _h, bi); } return ret; @@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ void State::commit() { - m_touched += dev::eth::commit(m_cache, m_db, m_state); + m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } @@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc) return sync(_bc, _bc.currentHash()); } -bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, ImportRequirements::value _ir) +bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi) { - (void)_ir; bool ret = false; // BLOCK BlockInfo bi = _bi ? _bi : _bc.info(_block); @@ -355,7 +342,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor { cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; - cwarn << "Bailing."; + cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); } m_previousBlock = bi; @@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) { #if ETH_TIMED_ENACTMENTS Timer t; @@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor #endif m_previousBlock = biParent; - auto ret = enact(_block, _bc, _ir); + auto ret = enact(_block, _bc); #if ETH_TIMED_ENACTMENTS enactment = t.elapsed(); @@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire RLP rlp(_block); cleanup(false); - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal); m_currentBlock = bi; m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); @@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) { DEV_TIMED_FUNCTION_ABOVE(500); @@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = _block.info; m_currentBlock.noteDirty(); + m_currentBlock = _block.info; // cnote << "playback begins:" << m_state.root(); // cnote << m_state; @@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } @@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } excluded.insert(h); - BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); + // IgnoreSeal since it's a VerifiedBlock. + BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; if (!_bc.isKnown(uncle.parentHash)) @@ -829,6 +817,8 @@ void State::uncommitToMine() bool State::amIJustParanoid(BlockChain const& _bc) { + (void)_bc; + /* commitToMine(_bc); // Update difficulty according to timestamp. @@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out(), std::function(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) { cwarn << "Bad block: " << _e.what(); } - +*/ return false; } @@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) for (auto const& u: us) if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. { - BlockInfo ubi(_bc.block(u)); - ubi.streamRLP(unclesData, WithProof); + uncleBlockHeaders.push_back(_bc.info(u)); + unclesData.appendRaw(_bc.headerData(u)); ++unclesCount; - uncleBlockHeaders.push_back(ubi); if (unclesCount == 2) break; } @@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) m_committedToMine = true; } -void State::completeMine() +bool State::sealBlock(bytesConstRef _header) { - cdebug << "Completing mine!"; + if (!m_committedToMine) + return false; + + cdebug << "Sealing block!"; // Got it! // Compile block: RLPStream ret; ret.appendList(3); - m_currentBlock.streamRLP(ret, WithProof); + ret.appendRaw(_header); ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); - m_currentBlock.noteDirty(); + m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; -/* StructuredLogger::minedNewBlock( + // TODO: move into Sealer + StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), - m_currentBlock.proof.nonce.abridged(), + "", // Can't give the nonce here. "", //TODO: chain head hash here ?? m_currentBlock.parentHash.abridged() - );*/ + ); // Quickly reset the transactions. // TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. @@ -989,6 +982,8 @@ void State::completeMine() m_receipts.clear(); m_transactionSet.clear(); m_lastTx = m_db; + + return true; } bool State::addressInUse(Address _id) const diff --git a/libethereum/State.h b/libethereum/State.h index f6a8471ea..805215ee5 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include "Account.h" @@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati enum class BaseState { PreExisting, - Empty, - CanonGenesis + Empty }; enum class Permanence @@ -104,6 +102,7 @@ class State friend class dev::test::ImportTest; friend class dev::test::StateLoader; friend class Executive; + friend class BlockChain; public: /// Default constructor; creates with a blank database prepopulated with the genesis block. @@ -125,7 +124,7 @@ public: ~State(); /// Construct state object from arbitrary point in blockchain. - PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::Default); + PopulationStatistics populateFromChain(BlockChain const& _bc, h256 const& _hash, ImportRequirements::value _ir = ImportRequirements::None); /// Set the coinbase address for any transactions we do. /// This causes a complete reset of current block. @@ -133,8 +132,8 @@ public: Address address() const { return m_ourAddress; } /// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. - static OverlayDB openDB(std::string const& _path, WithExisting _we = WithExisting::Trust); - static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } + static OverlayDB openDB(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust); + static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); } OverlayDB const& db() const { return m_db; } OverlayDB& db() { return m_db; } @@ -163,22 +162,20 @@ public: /// Pass in a solution to the proof-of-work. /// @returns true iff we were previously committed to mining. - template - bool completeMine(typename PoW::Solution const& _result) - { - if (!m_committedToMine) - return false; - - m_currentBlock.proof = _result; - if (!PoW::verify(m_currentBlock)) - return false; - -// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); - - completeMine(); - - return true; - } + /// TODO: verify it prior to calling this. + /** Commit to DB and build the final block if the previous call to mine()'s result is completion. + * Typically looks like: + * @code + * while (notYetMined) + * { + * // lock + * commitToMine(_blockChain); // will call uncommitToMine if a repeat. + * completeMine(); + * // unlock + * @endcode + */ + bool sealBlock(bytes const& _header) { return sealBlock(&_header); } + bool sealBlock(bytesConstRef _header); /// Get the complete current block, including valid nonce. /// Only valid after mine() returns true. @@ -295,11 +292,11 @@ public: bool sync(BlockChain const& _bc); /// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. - bool sync(BlockChain const& _bc, h256 _blockHash, BlockInfo const& _bi = BlockInfo(), ImportRequirements::value _ir = ImportRequirements::Default); + bool sync(BlockChain const& _bc, h256 const& _blockHash, BlockInfo const& _bi = BlockInfo()); /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -313,19 +310,6 @@ public: void resetCurrent(); private: - /** Commit to DB and build the final block if the previous call to mine()'s result is completion. - * Typically looks like: - * @code - * while (notYetMined) - * { - * // lock - * commitToMine(_blockChain); // will call uncommitToMine if a repeat. - * completeMine(); - * // unlock - * @endcode - */ - void completeMine(); - /// Undo the changes to the state for committing to mine. void uncommitToMine(); @@ -340,7 +324,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -386,7 +370,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, SecureTrieDB& _state) { AddressHash ret; for (auto const& i: _cache) @@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, } else { - SecureTrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(_state.db(), i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); @@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map const& _cache, DB& _db, if (i.second.isFreshCode()) { h256 ch = sha3(i.second.code()); - _db.insert(ch, &i.second.code()); + _state.db()->insert(ch, &i.second.code()); s << ch; } else diff --git a/libethereum/Utility.cpp b/libethereum/Utility.cpp index e02012cd5..1b97f82e7 100644 --- a/libethereum/Utility.cpp +++ b/libethereum/Utility.cpp @@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args) return m_data; } -void dev::eth::upgradeDatabase(std::string const& _basePath) +void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash) { std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath; @@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath) { auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; - auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash(); + auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash; string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4)); string extrasPath = chainPath + "/" + toString(databaseVersion); diff --git a/libethereum/Utility.h b/libethereum/Utility.h index 0dfe8509b..df48269ec 100644 --- a/libethereum/Utility.h +++ b/libethereum/Utility.h @@ -23,6 +23,7 @@ #include #include +#include namespace dev { @@ -42,7 +43,7 @@ namespace eth */ bytes parseData(std::string const& _args); -void upgradeDatabase(std::string const& _basePath); +void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash); } } diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 7d63ed165..15d39bded 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["logsBloom"] = toJS(_bi.logBloom); res["target"] = toJS(_bi.boundary()); -#if ETH_USING_ETHASH // TODO: move into ProofOfWork. - res["nonce"] = toJS(_bi.proof.nonce); - res["seedHash"] = toJS(_bi.proofCache()); -#endif +// res["nonce"] = toJS(_bi.proof.nonce); +// res["seedHash"] = toJS(_bi.proofCache()); } return res; } diff --git a/libweb3jsonrpc/JsonHelper.h b/libweb3jsonrpc/JsonHelper.h index 421d11b78..624a73e54 100644 --- a/libweb3jsonrpc/JsonHelper.h +++ b/libweb3jsonrpc/JsonHelper.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json); LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7. +template +Json::Value toJson(BlockHeaderPolished const& _bh) +{ + Json::Value res; + if (_bh) + { + res = toJson(static_cast(_bh)); + for (auto const& i: _bh.jsInfo()) + res[i.first] = i.second; + } + return res; +} + } namespace shh diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 1743882e5..061b5ae79 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -24,7 +24,6 @@ #include #include "../JsonSpiritHeaders.h" #include -#include #include #include #include "../TestHelper.h" @@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - Ethash::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header); BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index 452163061..e3f8ac29f 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex) CanonBlockChain bc; cout << bc; - State s(stateDB, BaseState::CanonGenesis, myMiner.address()); + State s = bc.genesisState(stateDB); + s.setAddress(myMiner.address()); cout << s; // Sync up - this won't do much until we use the last state. From 5ee3e8e5fc052ea6536c86cc40cb1a8c50191c4c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:29:03 +0200 Subject: [PATCH 17/22] All fields of BlockInfo now private. --- alethzero/MainWin.cpp | 34 +++--- ethminer/MinerAux.h | 4 +- evmjit/libevmjit-cpp/JitVM.cpp | 6 +- evmjit/libevmjit/RuntimeManager.cpp | 6 +- exp/main.cpp | 6 +- libethcore/BasicAuthority.cpp | 8 +- libethcore/BlockInfo.cpp | 104 ++++++++--------- libethcore/BlockInfo.h | 91 +++++++++------ libethcore/Common.cpp | 2 +- libethcore/Ethash.cpp | 40 +++---- libethcore/EthashAux.cpp | 2 +- libethereum/BasicGasPricer.cpp | 6 +- libethereum/BlockChain.cpp | 78 +++++-------- libethereum/BlockChain.h | 2 +- libethereum/BlockChainSync.cpp | 6 +- libethereum/BlockQueue.cpp | 50 ++++---- libethereum/Executive.cpp | 10 +- libethereum/State.cpp | 133 +++++++++++----------- libethereum/State.h | 2 +- libevm/ExtVMFace.h | 4 +- libevm/VM.cpp | 10 +- libtestutils/BlockChainLoader.cpp | 2 +- libweb3jsonrpc/JsonHelper.cpp | 22 ++-- test/TestHelper.cpp | 6 +- test/libethereum/ClientBase.cpp | 18 +-- test/libethereum/blockchain.cpp | 78 ++++++------- test/libethereum/genesis.cpp | 2 +- test/libevm/vm.cpp | 12 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- third/MainWin.cpp | 2 +- 30 files changed, 378 insertions(+), 370 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 2ee8928f5..ad8f5528c 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,7 +189,7 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto block = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; @@ -1629,7 +1629,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1706,7 +1706,7 @@ void Main::on_blocks_currentItemChanged() if (item->data(Qt::UserRole + 1).isNull()) { char timestamp[64]; - time_t rawTime = (time_t)(uint64_t)info.timestamp; + time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; s << "

#" << info.number; @@ -1714,7 +1714,7 @@ void Main::on_blocks_currentItemChanged() s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; - s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress)) << " " << info.coinbaseAddress << "" << "
"; + s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; s << "
Mix hash: " << info.mixHash << "" << "
"; s << "
Nonce: " << info.nonce << "" << "
"; @@ -1724,7 +1724,7 @@ void Main::on_blocks_currentItemChanged() { auto e = EthashAux::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; - s << "
Parent: " << info.parentHash << "" << "
"; + s << "
Parent: " << info.parentHash() << "" << "
"; } else { @@ -1732,20 +1732,20 @@ void Main::on_blocks_currentItemChanged() s << "
Parent: It was a virgin birth
"; } // s << "
Bloom: " << details.bloom << ""; - if (!!info.logBloom) - s << "
Log Bloom: " << info.logBloom << "
"; + if (!!info.logBloom()) + s << "
Log Bloom: " << info.logBloom() << "
"; else s << "
Log Bloom: Uneventful
"; - s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot << "" << "
"; - s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles << "" << "
"; + s << "
Transactions: " << block[1].itemCount() << " @" << info.transactionsRoot() << "" << "
"; + s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { BlockInfo uncle = BlockInfo::fromHeader(u.data()); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; - s << line << "Parent: " << uncle.parentHash << "" << "
"; + s << line << "Parent: " << uncle.parentHash() << "" << ""; s << line << "Number: " << uncle.number << "" << ""; - s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress)) << " " << uncle.coinbaseAddress << "" << ""; + s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; s << line << "Mix hash: " << uncle.mixHash << "" << ""; s << line << "Nonce: " << uncle.nonce << "" << ""; @@ -1754,20 +1754,20 @@ void Main::on_blocks_currentItemChanged() auto e = EthashAux::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } - if (info.parentHash) - s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash)).stateRoot << "" << "
"; + if (info.parentHash()) + s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; else s << "
Pre: Nothing is before Phil" << "
"; - s << "
Receipts: @" << info.receiptsRoot << ":" << "
"; + s << "
Receipts: @" << info.receiptsRoot() << ":" << "
"; BlockReceipts receipts = ethereum()->blockChain().receipts(h); unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } - s << "
Post: " << info.stateRoot << "" << "
"; + s << "
Post: " << info.stateRoot() << "" << "
"; s << "
Dump: " Span(Mono) << toHex(block[0].data()) << "" << "
"; s << "
Receipts-Hex: " Span(Mono) << toHex(receipts.rlp()) << "
"; } @@ -1807,7 +1807,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot().abridged() << "
"; + s << "
End State: " << receipt.stateRoot()().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 61fde605d..0d227b1ef 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -398,8 +398,8 @@ private: void doInitDAG(unsigned _n) { BlockInfo bi; - bi.number = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; + bi.number() = _n; + cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; Ethash::prep(bi); exit(0); } diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 2fb2a0e67..4e1fb66ea 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -24,7 +24,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -41,11 +41,11 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.caller = eth2jit(fromAddress(_ext.caller)); m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); - m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress)); + m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp = static_cast(_ext.currentBlock.timestamp); + m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index d48b64bb1..b2c15d7ae 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -1,7 +1,7 @@ #include "RuntimeManager.h" -#include "preprocessor/llvm_includes_start.h" -#include +#include "preprocessor/llvm_includes_start.h" +#include #include "preprocessor/llvm_includes_end.h" #include "Stack.h" @@ -77,7 +77,7 @@ llvm::Twine getName(RuntimeData::Index _index) case RuntimeData::Difficulty: return "block.difficulty"; case RuntimeData::GasLimit: return "block.gaslimit"; case RuntimeData::Number: return "block.number"; - case RuntimeData::Timestamp: return "block.timestamp"; + case RuntimeData::Timestamp: return "block.timestamp()"; case RuntimeData::Code: return "code.ptr"; case RuntimeData::CodeSize: return "code.size"; } diff --git a/exp/main.cpp b/exp/main.cpp index 4a35068f1..0b740e526 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -85,8 +85,8 @@ int main() BlockInfo bi; bi.difficulty = c_genesisDifficulty; bi.gasLimit = c_genesisGasLimit; - bi.number = 1; - bi.parentHash = sha3("parentHash"); + bi.number() = 1; + bi.parentHash() = sha3("parentHash"); bytes sealedData; @@ -329,7 +329,7 @@ int main() mine(s, bc, se); bytes minedBlock = s.blockData(); - cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot; + cnote << "Mined block is" << BlockInfo(minedBlock).stateRoot(); bc.import(minedBlock, stateDB); cnote << bc; diff --git a/libethcore/BasicAuthority.cpp b/libethcore/BasicAuthority.cpp index 22da67080..7ef3dd21e 100644 --- a/libethcore/BasicAuthority.cpp +++ b/libethcore/BasicAuthority.cpp @@ -44,19 +44,19 @@ void BasicAuthority::BlockHeaderRaw::populateFromHeader(RLP const& _header, Stri m_sig = _header[BlockInfo::BasicFields].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); BOOST_THROW_EXCEPTION(ex); } } diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 64961bc40..266f57cc8 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -32,7 +32,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -BlockInfo::BlockInfo(): timestamp(Invalid256) +BlockInfo::BlockInfo(): m_timestamp(Invalid256) { } @@ -45,26 +45,26 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, void BlockInfo::clear() { - parentHash = h256(); - sha3Uncles = EmptyListSHA3; - coinbaseAddress = Address(); - stateRoot = EmptyTrie; - transactionsRoot = EmptyTrie; - receiptsRoot = EmptyTrie; - logBloom = LogBloom(); - difficulty = 0; - number = 0; - gasLimit = 0; - gasUsed = 0; - timestamp = 0; - extraData.clear(); + m_parentHash = h256(); + m_sha3Uncles = EmptyListSHA3; + m_coinbaseAddress = Address(); + m_stateRoot = EmptyTrie; + m_transactionsRoot = EmptyTrie; + m_receiptsRoot = EmptyTrie; + m_logBloom = LogBloom(); + m_difficulty = 0; + m_number = 0; + m_gasLimit = 0; + m_gasUsed = 0; + m_timestamp = 0; + m_extraData.clear(); noteDirty(); } h256 const& BlockInfo::boundary() const { - if (!m_boundary && difficulty) - m_boundary = (h256)(u256)((bigint(1) << 256) / difficulty); + if (!m_boundary && m_difficulty) + m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty); return m_boundary; } @@ -81,8 +81,8 @@ h256 const& BlockInfo::hashWithout() const void BlockInfo::streamRLPFields(RLPStream& _s) const { - _s << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom - << difficulty << number << gasLimit << gasUsed << timestamp << extraData; + _s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom + << m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData; } h256 BlockInfo::headerHashFromBlock(bytesConstRef _block) @@ -110,19 +110,19 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) int field = 0; try { - parentHash = _header[field = 0].toHash(RLP::VeryStrict); - sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); - coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); - stateRoot = _header[field = 3].toHash(RLP::VeryStrict); - transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); - receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); - logBloom = _header[field = 6].toHash(RLP::VeryStrict); - difficulty = _header[field = 7].toInt(); - number = _header[field = 8].toInt(); - gasLimit = _header[field = 9].toInt(); - gasUsed = _header[field = 10].toInt(); - timestamp = _header[field = 11].toInt(); - extraData = _header[field = 12].toBytes(); + m_parentHash = _header[field = 0].toHash(RLP::VeryStrict); + m_sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); + m_coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); + m_stateRoot = _header[field = 3].toHash(RLP::VeryStrict); + m_transactionsRoot = _header[field = 4].toHash(RLP::VeryStrict); + m_receiptsRoot = _header[field = 5].toHash(RLP::VeryStrict); + m_logBloom = _header[field = 6].toHash(RLP::VeryStrict); + m_difficulty = _header[field = 7].toInt(); + m_number = _header[field = 8].toInt(); + m_gasLimit = _header[field = 9].toInt(); + m_gasUsed = _header[field = 10].toInt(); + m_timestamp = _header[field = 11].toInt(); + m_extraData = _header[field = 12].toBytes(); } catch (Exception const& _e) { @@ -130,11 +130,11 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s) throw; } - if (number > ~(unsigned)0) + if (m_number > ~(unsigned)0) BOOST_THROW_EXCEPTION(InvalidNumber()); - if (_s != CheckNothing && gasUsed > gasLimit) - BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) ); + if (_s != CheckNothing && m_gasUsed > m_gasLimit) + BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed))); } struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "▧" EthWhite " ◌"; } static const int verbosity = 9; }; @@ -147,7 +147,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data().toBytes(); }); clog(BlockInfoDiagnosticsChannel) << "Expected trie root:" << toString(expectedRoot); - if (transactionsRoot != expectedRoot) + if (m_transactionsRoot != expectedRoot) { MemoryDB tm; GenericTrieDB transactionsTrie(&tm); @@ -172,52 +172,52 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) cdebug << toHex(t); - BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, transactionsRoot)); + BOOST_THROW_EXCEPTION(InvalidTransactionsRoot() << Hash256RequirementError(expectedRoot, m_transactionsRoot)); } clog(BlockInfoDiagnosticsChannel) << "Expected uncle hash:" << toString(sha3(root[2].data())); - if (sha3Uncles != sha3(root[2].data())) + if (m_sha3Uncles != sha3(root[2].data())) BOOST_THROW_EXCEPTION(InvalidUnclesHash()); } void BlockInfo::populateFromParent(BlockInfo const& _parent) { - stateRoot = _parent.stateRoot; - number = _parent.number + 1; - gasLimit = selectGasLimit(_parent); - gasUsed = 0; - difficulty = calculateDifficulty(_parent); - parentHash = _parent.hash(); + m_stateRoot = _parent.stateRoot(); + m_number = _parent.m_number + 1; + m_gasLimit = selectGasLimit(_parent); + m_gasUsed = 0; + m_difficulty = calculateDifficulty(_parent); + m_parentHash = _parent.hash(); } u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return c_genesisGasLimit; else // target minimum of 3141592 - if (_parent.gasLimit < c_genesisGasLimit) - return min(c_genesisGasLimit, _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor - 1); + if (_parent.m_gasLimit < c_genesisGasLimit) + return min(c_genesisGasLimit, _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor - 1); else - return max(c_genesisGasLimit, _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.gasUsed * 6 / 5) / c_gasLimitBoundDivisor); + return max(c_genesisGasLimit, _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor + 1 + (_parent.m_gasUsed * 6 / 5) / c_gasLimitBoundDivisor); } u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const { - if (!parentHash) + if (!m_parentHash) return (u256)c_genesisDifficulty; else - return max(c_minimumDifficulty, timestamp >= _parent.timestamp + c_durationLimit ? _parent.difficulty - (_parent.difficulty / c_difficultyBoundDivisor) : (_parent.difficulty + (_parent.difficulty / c_difficultyBoundDivisor))); + return max(c_minimumDifficulty, m_timestamp >= _parent.m_timestamp + c_durationLimit ? _parent.m_difficulty - (_parent.m_difficulty / c_difficultyBoundDivisor) : (_parent.m_difficulty + (_parent.m_difficulty / c_difficultyBoundDivisor))); } void BlockInfo::verifyParent(BlockInfo const& _parent) const { // Check timestamp is after previous timestamp. - if (parentHash) + if (m_parentHash) { - if (timestamp <= _parent.timestamp) + if (m_timestamp <= _parent.m_timestamp) BOOST_THROW_EXCEPTION(InvalidTimestamp()); - if (number != _parent.number + 1) + if (m_number != _parent.m_number + 1) BOOST_THROW_EXCEPTION(InvalidNumber()); } } diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index b00fa73fb..67a5397f4 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -81,21 +81,6 @@ struct BlockInfo public: static const unsigned BasicFields = 13; - // TODO: make them all private! - h256 parentHash; - h256 sha3Uncles; - Address coinbaseAddress; - h256 stateRoot; - h256 transactionsRoot; - h256 receiptsRoot; - LogBloom logBloom; - u256 difficulty; // TODO: pull out into BlockHeader - u256 number; - u256 gasLimit; - u256 gasUsed; - u256 timestamp = Invalid256; - bytes extraData; - BlockInfo(); explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData); explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {} @@ -104,23 +89,23 @@ public: static h256 headerHashFromBlock(bytesConstRef _block); static RLP extractHeader(bytesConstRef _block); - explicit operator bool() const { return timestamp != Invalid256; } + explicit operator bool() const { return m_timestamp != Invalid256; } bool operator==(BlockInfo const& _cmp) const { - return parentHash == _cmp.parentHash && - sha3Uncles == _cmp.sha3Uncles && - coinbaseAddress == _cmp.coinbaseAddress && - stateRoot == _cmp.stateRoot && - transactionsRoot == _cmp.transactionsRoot && - receiptsRoot == _cmp.receiptsRoot && - logBloom == _cmp.logBloom && - difficulty == _cmp.difficulty && - number == _cmp.number && - gasLimit == _cmp.gasLimit && - gasUsed == _cmp.gasUsed && - timestamp == _cmp.timestamp && - extraData == _cmp.extraData; + return m_parentHash == _cmp.parentHash() && + m_sha3Uncles == _cmp.sha3Uncles() && + m_coinbaseAddress == _cmp.coinbaseAddress() && + m_stateRoot == _cmp.stateRoot() && + m_transactionsRoot == _cmp.transactionsRoot() && + m_receiptsRoot == _cmp.receiptsRoot() && + m_logBloom == _cmp.logBloom() && + m_difficulty == _cmp.difficulty() && + m_number == _cmp.number() && + m_gasLimit == _cmp.gasLimit() && + m_gasUsed == _cmp.gasUsed() && + m_timestamp == _cmp.timestamp() && + m_extraData == _cmp.extraData(); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } @@ -132,6 +117,31 @@ public: u256 selectGasLimit(BlockInfo const& _parent) const; h256 const& boundary() const; + h256 const& parentHash() const { return m_parentHash; } + h256 const& sha3Uncles() const { return m_sha3Uncles; } + + void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); } + void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); } + void setTimestamp(u256 const& _v) { m_timestamp = _v; noteDirty(); } + void setCoinbaseAddress(Address const& _v) { m_coinbaseAddress = _v; noteDirty(); } + void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); } + void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } + void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } + void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + + Address const& coinbaseAddress() const { return m_coinbaseAddress; } + h256 const& stateRoot() const { return m_stateRoot; } + h256 const& transactionsRoot() const { return m_transactionsRoot; } + h256 const& receiptsRoot() const { return m_receiptsRoot; } + LogBloom const& logBloom() const { return m_logBloom; } + u256 const& number() const { return m_number; } + u256 const& gasLimit() const { return m_gasLimit; } + u256 const& gasUsed() const { return m_gasUsed; } + u256 const& timestamp() const { return m_timestamp; } + bytes const& extraData() const { return m_extraData; } + + u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader + /// sha3 of the header only. h256 const& hashWithout() const; h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); } @@ -145,6 +155,21 @@ protected: mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised. + h256 m_parentHash; + h256 m_sha3Uncles; + Address m_coinbaseAddress; + h256 m_stateRoot; + h256 m_transactionsRoot; + h256 m_receiptsRoot; + LogBloom m_logBloom; + u256 m_number; + u256 m_gasLimit; + u256 m_gasUsed; + u256 m_timestamp = Invalid256; + bytes m_extraData; + + u256 m_difficulty; // TODO: pull out into BlockHeader + private: mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised. mutable h256 m_boundary; ///< 2^256 / difficulty @@ -152,9 +177,9 @@ private: inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) { - _out << _bi.hashWithout() << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << - _bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " << - _bi.gasUsed << " " << _bi.timestamp; + _out << _bi.hashWithout() << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.coinbaseAddress() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " << + _bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " << + _bi.gasUsed() << " " << _bi.timestamp(); return _out; } @@ -191,7 +216,7 @@ public: // TODO: consider making private. void verifyParent(BlockHeaderPolished const& _parent) { - if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) + if (BlockInfo::parentHash() && BlockInfo::parentHash() != _parent.hash()) BOOST_THROW_EXCEPTION(InvalidParentHash()); BlockInfo::verifyParent(_parent); BlockInfoSub::verifyParent(_parent); diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 499854584..05cc45280 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -124,7 +124,7 @@ static void badBlockInfo(BlockInfo const& _bi, string const& _err) ss << c_space << endl; ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; ss << c_space << endl; - string bin = toString(_bi.number); + string bin = toString(_bi.number()); ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; ss << c_space << endl; ss << c_line; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 128822b80..ee483aa8b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -62,7 +62,7 @@ namespace eth h256 const& Ethash::BlockHeaderRaw::seedHash() const { if (!m_seedHash) - m_seedHash = EthashAux::seedHash((unsigned)number); + m_seedHash = EthashAux::seedHash((unsigned)m_number); return m_seedHash; } @@ -72,7 +72,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ m_nonce = _header[BlockInfo::BasicFields + 1].toHash(); // check it hashes according to proof of work or that it's the genesis block. - if (_s == CheckEverything && parentHash && !verify()) + if (_s == CheckEverything && m_parentHash && !verify()) { InvalidBlockNonce ex; ex << errinfo_nonce(m_nonce); @@ -81,42 +81,42 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _ EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce); ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash)); ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_target(boundary()); BOOST_THROW_EXCEPTION(ex); } - else if (_s == QuickNonce && parentHash && !preVerify()) + else if (_s == QuickNonce && m_parentHash && !preVerify()) { InvalidBlockNonce ex; ex << errinfo_hash256(hashWithout()); - ex << errinfo_difficulty(difficulty); + ex << errinfo_difficulty(m_difficulty); ex << errinfo_nonce(m_nonce); BOOST_THROW_EXCEPTION(ex); } if (_s != CheckNothing) { - if (difficulty < c_minimumDifficulty) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) ); + if (m_difficulty < c_minimumDifficulty) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(m_difficulty)) ); - if (gasLimit < c_minGasLimit) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) ); + if (m_gasLimit < c_minGasLimit) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(m_gasLimit)) ); - if (number && extraData.size() > c_maximumExtraDataSize) - BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size()))); + if (m_number && m_extraData.size() > c_maximumExtraDataSize) + BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(m_extraData.size()))); } } void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent) { // Check difficulty is correct given the two timestamps. - if (difficulty != calculateDifficulty(_parent)) - BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty)); + if (m_difficulty != calculateDifficulty(_parent)) + BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)m_difficulty)); - if (gasLimit < c_minGasLimit || - gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor || - gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor) - BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)); + if (m_gasLimit < c_minGasLimit || + m_gasLimit <= _parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor || + m_gasLimit >= _parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor) + BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.m_gasLimit - _parent.m_gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)m_gasLimit) << errinfo_max((bigint)_parent.m_gasLimit + _parent.m_gasLimit / c_gasLimitBoundDivisor)); } void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) @@ -126,7 +126,7 @@ void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent) bool Ethash::BlockHeaderRaw::preVerify() const { - if (number >= ETHASH_EPOCH_LENGTH * 2048) + if (m_number >= ETHASH_EPOCH_LENGTH * 2048) return false; bool ret = !!ethash_quick_check_difficulty( @@ -162,7 +162,7 @@ bool Ethash::BlockHeaderRaw::verify() const cwarn << "headerHash:" << hashWithout(); cwarn << "nonce:" << m_nonce; cwarn << "mixHash:" << m_mixHash; - cwarn << "difficulty:" << difficulty; + cwarn << "difficulty:" << m_difficulty; cwarn << "boundary:" << boundary(); cwarn << "result.value:" << result.value; cwarn << "result.mixHash:" << result.mixHash; @@ -290,7 +290,7 @@ public: m_farm.setWork(m_sealing); m_farm.start(m_sealer); m_farm.setWork(m_sealing); // TODO: take out one before or one after... - Ethash::ensurePrecomputed((unsigned)_bi.number); + Ethash::ensurePrecomputed((unsigned)_bi.number()); } void onSealGenerated(std::function const& _f) override { diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index c511978db..763bea417 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -63,7 +63,7 @@ EthashAux* EthashAux::get() uint64_t EthashAux::cacheSize(BlockInfo const& _header) { - return ethash_get_cachesize((uint64_t)_header.number); + return ethash_get_cachesize((uint64_t)_header.number()); } uint64_t EthashAux::dataSize(uint64_t _blockNumber) diff --git a/libethereum/BasicGasPricer.cpp b/libethereum/BasicGasPricer.cpp index 145d23594..b957966f8 100644 --- a/libethereum/BasicGasPricer.cpp +++ b/libethereum/BasicGasPricer.cpp @@ -30,7 +30,7 @@ void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; h256 p = _bc.currentHash(); - m_gasPerBlock = _bc.info(p).gasLimit; + m_gasPerBlock = _bc.info(p).gasLimit(); map dist; u256 total = 0; @@ -39,7 +39,7 @@ void BasicGasPricer::update(BlockChain const& _bc) while (c < 1000 && p) { BlockInfo bi = _bc.info(p); - if (bi.transactionsRoot != EmptyTrie) + if (bi.transactionsRoot() != EmptyTrie) { auto bb = _bc.block(p); RLP r(bb); @@ -54,7 +54,7 @@ void BasicGasPricer::update(BlockChain const& _bc) i++; } } - p = bi.parentHash; + p = bi.parentHash(); ++c; } diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index aae8cbd10..b696c77bd 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -72,7 +72,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, BlockChain const& _bc) { try { BlockInfo d(bytesConstRef(it->value())); - _out << toHex(it->key().ToString()) << ": " << d.number << " @ " << d.parentHash << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; + _out << toHex(it->key().ToString()) << ": " << d.number() << " @ " << d.parentHash() << (cmp == it->key().ToString() ? " BEST" : "") << std::endl; } catch (...) { cwarn << "Invalid DB entry:" << toHex(it->key().ToString()) << " -> " << toHex(bytesConstRef(it->value())); @@ -293,11 +293,11 @@ void BlockChain::rebuild(std::string const& _path, std::function parent is" << bi.parentHash << "; expected" << lastHash << "#" << (d - 1); + cwarn << "DISJOINT CHAIN DETECTED; " << bi.hash() << "#" << d << " -> parent is" << bi.parentHash() << "; expected" << lastHash << "#" << (d - 1); return; } lastHash = bi.hash(); @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) + DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; @@ -461,21 +461,21 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Work out its number as the parent's number + 1 - if (!isKnown(_block.info.parentHash)) + if (!isKnown(_block.info.parentHash())) { - clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash(); // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_block.info.parentHash); + auto pd = details(_block.info.parentHash()); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_block.info.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; + auto parentBlock = block(_block.info.parentHash()); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash()); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number(); clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -483,9 +483,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& } // Check it's not crazy - if (_block.info.timestamp > (u256)time(0)) + if (_block.info.timestamp() > (u256)time(0)) { - clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp() << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } @@ -543,9 +543,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_block.info.parentHash); + details(_block.info.parentHash()); DEV_WRITE_GUARDED(x_details) - m_details[_block.info.parentHash].children.push_back(_block.info.hash()); + m_details[_block.info.parentHash()].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); @@ -554,9 +554,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash()].rlp())); - extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash(), {}).rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); @@ -585,10 +585,10 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _block.info.proof.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif - // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; + // cnote << "Parent " << bi.parentHash() << " has " << details(bi.parentHash()).children.size() << " children."; h256s route; h256 common; @@ -599,7 +599,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash()); route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be @@ -630,15 +630,15 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& // Collate logs into blooms. h256s alteredBlooms; { - LogBloom blockBloom = tbi.logBloom; - blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress.ref())); + LogBloom blockBloom = tbi.logBloom(); + blockBloom.shiftBloom<3>(sha3(tbi.coinbaseAddress().ref())); // Pre-memoize everything we need before locking x_blocksBlooms - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) blocksBlooms(chunkId(level, index / c_bloomIndexSize)); WriteGuard l(x_blocksBlooms); - for (unsigned level = 0, index = (unsigned)tbi.number; level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) + for (unsigned level = 0, index = (unsigned)tbi.number(); level < c_bloomIndexLevels; level++, index /= c_bloomIndexSize) { unsigned i = index / c_bloomIndexSize; unsigned o = index % c_bloomIndexSize; @@ -661,23 +661,23 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& ReadGuard l1(x_blocksBlooms); for (auto const& h: alteredBlooms) extrasBatch.Put(toSlice(h, ExtraBlocksBlooms), (ldb::Slice)dev::ref(m_blocksBlooms[h].rlp())); - extrasBatch.Put(toSlice(h256(tbi.number), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); + extrasBatch.Put(toSlice(h256(tbi.number()), ExtraBlockHash), (ldb::Slice)dev::ref(BlockHash(tbi.hash()).rlp())); } // FINALLY! change our best hash. { newLastBlockHash = _block.info.hash(); - newLastBlockNumber = (unsigned)_block.info.number; + newLastBlockNumber = (unsigned)_block.info.number(); } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number() << "). Has" << (details(_block.info.parentHash()).children.size() - 1) << "siblings. Route:" << route; #if ETH_USING_ETHASH StructuredLogger::chainNewHead( _block.info.headerHash(WithoutProof).abridged(), _block.info.proof.nonce.abridged(), currentHash().abridged(), - _block.info.parentHash.abridged() + _block.info.parentHash().abridged() ); #endif } @@ -750,7 +750,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& checkBest = t.elapsed(); if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number(); cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; @@ -758,7 +758,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; cnote << " " << _block.transactions.size() << " transactions"; - cnote << " " << _block.info.gasUsed << " gas used"; + cnote << " " << _block.info.gasUsed() << " gas used"; } #endif @@ -861,7 +861,7 @@ void BlockChain::rescue(OverlayDB& _db) cout << "extras..." << flush; details(h); cout << "state..." << flush; - if (_db.exists(bi.stateRoot)) + if (_db.exists(bi.stateRoot())) break; } catch (...) {} @@ -1233,19 +1233,3 @@ State BlockChain::genesisState(OverlayDB const& _db) return ret; } - - - - - - - - - - - - - - - - diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 50965f2b6..3ff85c8a6 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -391,7 +391,7 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash)); + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index ed022fb75..2141c4587 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -111,7 +111,7 @@ void BlockChainSync::onPeerStatus(std::shared_ptr _peer) unsigned BlockChainSync::estimatedHashes() const { BlockInfo block = host().chain().info(); - time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp; + time_t lastBlockTime = (block.hash() == host().chain().genesisHash()) ? 1428192000 : (time_t)block.timestamp(); time_t now = time(0); unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) @@ -220,9 +220,9 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const if (m_state == SyncState::NewBlocks) { BlockInfo bi(_r[i].data()); - if (bi.number > maxUnknownNumber) + if (bi.number() > maxUnknownNumber) { - maxUnknownNumber = bi.number; + maxUnknownNumber = bi.number(); maxUnknown = h; } } diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 6b400b236..c9ee4c1cf 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -101,8 +101,8 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.sha3Uncles = work.hash; - bi.parentHash = work.parentHash; + bi.setSha3Uncles(work.hash); + bi.setParentHash(work.parentHash); m_verifying.emplace_back(move(bi)); } @@ -121,7 +121,7 @@ void BlockQueue::verifierBody() m_readySet.erase(work.hash); m_knownBad.insert(work.hash); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->verified.info.sha3Uncles == work.hash) + if (it->verified.info.sha3Uncles() == work.hash) { m_verifying.erase(it); goto OK1; @@ -136,11 +136,11 @@ void BlockQueue::verifierBody() { WriteGuard l2(m_lock); unique_lock l(m_verification); - if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles == work.hash) + if (!m_verifying.empty() && m_verifying.front().verified.info.sha3Uncles() == work.hash) { // we're next! m_verifying.pop_front(); - if (m_knownBad.count(res.verified.info.parentHash)) + if (m_knownBad.count(res.verified.info.parentHash())) { m_readySet.erase(res.verified.info.hash()); m_knownBad.insert(res.verified.info.hash()); @@ -154,7 +154,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.verified.info.sha3Uncles == work.hash) + if (i.verified.info.sha3Uncles() == work.hash) { i = move(res); goto OK; @@ -172,7 +172,7 @@ void BlockQueue::drainVerified_WITH_BOTH_LOCKS() { while (!m_verifying.empty() && !m_verifying.front().blockData.empty()) { - if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + if (m_knownBad.count(m_verifying.front().verified.info.parentHash())) { m_readySet.erase(m_verifying.front().verified.info.hash()); m_knownBad.insert(m_verifying.front().verified.info.hash()); @@ -213,7 +213,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) return ImportResult::Malformed; } - clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash; + clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number() << "parent is" << bi.parentHash(); // Check block doesn't already exist first! if (m_bc->isKnown(h)) @@ -227,38 +227,38 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // Check it's not in the future (void)_isOurs; - if (bi.timestamp > (u256)time(0)/* && !_isOurs*/) + if (bi.timestamp() > (u256)time(0)/* && !_isOurs*/) { - m_future.insert(make_pair((unsigned)bi.timestamp, make_pair(h, _block.toBytes()))); + m_future.insert(make_pair((unsigned)bi.timestamp(), make_pair(h, _block.toBytes()))); char buf[24]; - time_t bit = (unsigned)bi.timestamp; + time_t bit = (unsigned)bi.timestamp(); if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails - clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp() << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; - m_difficulty += bi.difficulty; - bool unknown = !m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash); + m_difficulty += bi.difficulty(); + bool unknown = !m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash()); return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown; } else { // We now know it. - if (m_knownBad.count(bi.parentHash)) + if (m_knownBad.count(bi.parentHash())) { m_knownBad.insert(bi.hash()); updateBad_WITH_LOCK(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } - else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !m_bc->isKnown(bi.parentHash)) + else if (!m_readySet.count(bi.parentHash()) && !m_drainingSet.count(bi.parentHash()) && !m_bc->isKnown(bi.parentHash())) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash; - m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); + clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash(); + m_unknown.insert(make_pair(bi.parentHash(), make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); m_unknownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_unknownCount++; return ImportResult::UnknownParent; @@ -268,11 +268,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, bool _isOurs) // If valid, append to blocks. clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash(), _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); m_knownSize += _block.size(); - m_difficulty += bi.difficulty; + m_difficulty += bi.difficulty(); m_knownCount++; noteReady_WITH_LOCK(h); @@ -295,7 +295,7 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::vector oldVerified; swap(m_verified, oldVerified); for (auto& b: oldVerified) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.hash())) { m_knownBad.insert(b.verified.info.hash()); m_readySet.erase(b.verified.info.hash()); @@ -321,9 +321,9 @@ void BlockQueue::updateBad_WITH_LOCK(h256 const& _bad) std::deque oldVerifying; swap(m_verifying, oldVerifying); for (auto& b: oldVerifying) - if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.sha3Uncles)) + if (m_knownBad.count(b.verified.info.parentHash()) || m_knownBad.count(b.verified.info.sha3Uncles())) { - h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles; + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.sha3Uncles(); m_knownBad.insert(h); m_readySet.erase(h); collectUnknownBad_WITH_BOTH_LOCKS(h); @@ -460,7 +460,7 @@ void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) // TODO: @optimise use map rather than vector & set. auto h = bs.verified.info.hash(); m_drainingSet.insert(h); - m_drainingDifficulty += bs.verified.info.difficulty; + m_drainingDifficulty += bs.verified.info.difficulty(); m_readySet.erase(h); m_knownSize -= bs.verified.block.size(); m_knownCount--; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 866c9c8f9..e58e1a8c6 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -144,7 +144,7 @@ string StandardTrace::json(bool _styled) const Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), - m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), + m_lastHashes(_bc.lastHashes((unsigned)_s.info().number() - 1)), m_depth(_level) {} @@ -170,11 +170,11 @@ void Executive::initialize(Transaction const& _transaction) // Avoid transactions that would take us beyond the block gas limit. u256 startGasUsed = m_s.gasUsed(); - if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) + if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit()) { - clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit() - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; - BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); + BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit() - startGasUsed), (bigint)m_t.gas())); } // Check gas cost is enough. @@ -403,7 +403,7 @@ void Executive::finalize() m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); - m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); + m_s.addBalance(m_s.m_currentBlock.coinbaseAddress(), feesEarned); // Suicides... if (m_ext) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index ee2078a07..64daaf5f8 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -105,7 +105,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress): m_previousBlock.clear(); m_currentBlock.clear(); -// assert(m_state.root() == m_previousBlock.stateRoot); +// assert(m_state.root() == m_previousBlock.stateRoot()); paranoia("end of normal construction.", true); } @@ -123,16 +123,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& auto b = _bc.block(_h); BlockInfo bi(b); - if (bi.number) + if (bi.number()) { // Non-genesis: // 1. Start at parent's end state (state root). - BlockInfo bip(_bc.block(bi.parentHash)); - sync(_bc, bi.parentHash, bip); + BlockInfo bip(_bc.block(bi.parentHash())); + sync(_bc, bi.parentHash(), bip); // 2. Enact the block's transactions onto this state. - m_ourAddress = bi.coinbaseAddress; + m_ourAddress = bi.coinbaseAddress(); Timer t; auto vb = _bc.verifyBlock(&b, function(), _ir); ret.verify = t.elapsed(); @@ -338,9 +338,9 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // Find most recent state dump and replay what's left. // (Most recent state dump might end up being genesis.) - if (m_db.lookup(bi.stateRoot).empty()) + if (m_db.lookup(bi.stateRoot()).empty()) { - cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database."; + cwarn << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot() << "not found in database."; cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Try rescuing the database by running: eth --rescue"; exit(-1); @@ -357,10 +357,10 @@ bool State::sync(BlockChain const& _bc, h256 const& _block, BlockInfo const& _bi // (Most recent state dump might end up being genesis.) std::vector chain; - while (bi.number != 0 && m_db.lookup(bi.stateRoot).empty()) // while we don't have the state root of the latest block... + while (bi.number() != 0 && m_db.lookup(bi.stateRoot()).empty()) // while we don't have the state root of the latest block... { chain.push_back(bi.hash()); // push back for later replay. - bi.populate(_bc.block(bi.parentHash)); // move to parent. + bi.populate(_bc.block(bi.parentHash())); // move to parent. } m_previousBlock = bi; @@ -402,7 +402,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif // Check family: - BlockInfo biParent = _bc.info(_block.info.parentHash); + BlockInfo biParent = _bc.info(_block.info.parentHash()); _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS @@ -411,15 +411,15 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc) #endif BlockInfo biGrandParent; - if (biParent.number) - biGrandParent = _bc.info(biParent.parentHash); + if (biParent.number()) + biGrandParent = _bc.info(biParent.parentHash()); #if ETH_TIMED_ENACTMENTS populateGrand = t.elapsed(); t.restart(); #endif - sync(_bc, _block.info.parentHash, BlockInfo()); + sync(_bc, _block.info.parentHash(), BlockInfo()); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -462,17 +462,15 @@ void State::resetCurrent() m_cache.clear(); m_touched.clear(); m_currentBlock = BlockInfo(); - m_currentBlock.coinbaseAddress = m_ourAddress; - m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); - m_currentBlock.transactionsRoot = h256(); - m_currentBlock.sha3Uncles = h256(); + m_currentBlock.setCoinbaseAddress(m_ourAddress); + m_currentBlock.setTimestamp(max(m_previousBlock.timestamp() + 1, (u256)time(0))); m_currentBlock.populateFromParent(m_previousBlock); // Update timestamp according to clock. // TODO: check. m_lastTx = m_db; - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); m_committedToMine = false; @@ -538,7 +536,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu catch (BlockGasLimitReached const& e) { bigint const& got = *boost::get_error_info(e); - if (got > m_currentBlock.gasLimit) + if (got > m_currentBlock.gasLimit()) { clog(StateTrace) << t.sha3() << "Dropping over-gassy transaction (gas > block's gas limit)"; _tq.drop(t.sha3()); @@ -583,7 +581,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire m_currentBlock.verifyInternals(_block); m_currentBlock.noteDirty(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number()); string ret; unsigned i = 0; @@ -604,12 +602,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == _block.info.parentHash); - assert(m_currentBlock.parentHash == _block.info.parentHash); - assert(rootHash() == m_previousBlock.stateRoot); + assert(m_previousBlock.hash() == _block.info.parentHash()); + assert(m_currentBlock.parentHash() == _block.info.parentHash()); + assert(rootHash() == m_previousBlock.stateRoot()); #endif - if (m_currentBlock.parentHash != m_previousBlock.hash()) + if (m_currentBlock.parentHash() != m_previousBlock.hash()) // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); @@ -622,7 +620,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) LastHashes lh; DEV_TIMED_ABOVE("lastHashes", 500) - lh = _bc.lastHashes((unsigned)m_previousBlock.number); + lh = _bc.lastHashes((unsigned)m_previousBlock.number()); RLP rlp(_block.block); @@ -651,28 +649,28 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) } h256 receiptsRoot; - DEV_TIMED_ABOVE("receiptsRoot", 500) + DEV_TIMED_ABOVE(".receiptsRoot()", 500) receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) + if (receiptsRoot != m_currentBlock.receiptsRoot()) { InvalidReceiptsStateRoot ex; - ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot()); ex << errinfo_receipts(receipts); ex << errinfo_vmtrace(vmTrace(_block.block, _bc, ImportRequirements::None)); BOOST_THROW_EXCEPTION(ex); } - if (m_currentBlock.logBloom != logBloom()) + if (m_currentBlock.logBloom() != logBloom()) { InvalidLogBloom ex; - ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom()); ex << errinfo_receipts(receipts); BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. - u256 tdIncrease = m_currentBlock.difficulty; + u256 tdIncrease = m_currentBlock.difficulty(); // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) @@ -686,7 +684,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) vector rewarded; h256Hash excluded; DEV_TIMED_ABOVE("allKin", 500) - excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; @@ -710,22 +708,22 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) BlockInfo uncle(i.data(), IgnoreSeal, h, HeaderData); BlockInfo uncleParent; - if (!_bc.isKnown(uncle.parentHash)) + if (!_bc.isKnown(uncle.parentHash())) BOOST_THROW_EXCEPTION(UnknownParent()); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + uncleParent = BlockInfo(_bc.block(uncle.parentHash())); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + if ((bigint)uncleParent.number() < (bigint)m_currentBlock.number() - 7) { UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } - else if (uncle.number == m_currentBlock.number) + else if (uncle.number() == m_currentBlock.number()) { UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); + ex << errinfo_uncleNumber(uncle.number()); + ex << errinfo_currentNumber(m_currentBlock.number()); BOOST_THROW_EXCEPTION(ex); } uncle.verifyParent(uncleParent); @@ -748,17 +746,17 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. - if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) + if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash()) { m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot())); } - if (m_currentBlock.gasUsed != gasUsed()) + if (m_currentBlock.gasUsed() != gasUsed()) { // Rollback the trie. m_db.rollback(); - BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); + BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed()))); } return tdIncrease; @@ -772,7 +770,7 @@ void State::cleanup(bool _fullCommit) // Commit the new trie to disk. if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -786,7 +784,7 @@ void State::cleanup(bool _fullCommit) m_db.commit(); if (isChannelVisible()) // Avoid calling toHex if not needed - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot() << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -806,7 +804,7 @@ void State::uncommitToMine() { m_cache.clear(); if (!m_transactions.size()) - m_state.setRoot(m_previousBlock.stateRoot); + m_state.setRoot(m_previousBlock.stateRoot()); else m_state.setRoot(m_receipts.back().stateRoot()); m_db = m_lastTx; @@ -878,12 +876,12 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream unclesData; unsigned unclesCount = 0; - if (m_previousBlock.number != 0) + if (m_previousBlock.number() != 0) { // Find great-uncles (or second-cousins or whatever they are) - children of great-grandparents, great-great-grandparents... that were not already uncles in previous generations. -// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash << endl; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); - auto p = m_previousBlock.parentHash; +// cout << "Checking " << m_previousBlock.hash << ", parent=" << m_previousBlock.parentHash() << endl; + h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash(), 6); + auto p = m_previousBlock.parentHash(); for (unsigned gen = 0; gen < 6 && p != _bc.genesisHash() && unclesCount < 2; ++gen, p = _bc.details(p).parent) { auto us = _bc.details(p).children; @@ -926,11 +924,6 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) RLPStream(unclesCount).appendRaw(unclesData.out(), unclesCount).swapOut(m_currentUncles); - m_currentBlock.transactionsRoot = hash256(transactionsMap); - m_currentBlock.receiptsRoot = hash256(receiptsMap); - m_currentBlock.logBloom = logBloom(); - m_currentBlock.sha3Uncles = sha3(m_currentUncles); - // Apply rewards last of all. applyRewards(uncleBlockHeaders); @@ -941,12 +934,18 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData) // cnote << m_state; // cnote << *this; - m_currentBlock.gasUsed = gasUsed(); - m_currentBlock.stateRoot = m_state.root(); - m_currentBlock.parentHash = m_previousBlock.hash(); - m_currentBlock.extraData = _extraData; - if (m_currentBlock.extraData.size() > 32) - m_currentBlock.extraData.resize(32); + m_currentBlock.setLogBloom(logBloom()); + m_currentBlock.setGasUsed(gasUsed()); + m_currentBlock.setRoots(hash256(transactionsMap), hash256(receiptsMap), sha3(m_currentUncles), m_state.root()); + + m_currentBlock.setParentHash(m_previousBlock.hash()); + m_currentBlock.setExtraData(_extraData); + if (m_currentBlock.extraData().size() > 32) + { + auto ed = m_currentBlock.extraData(); + ed.resize(32); + m_currentBlock.setExtraData(ed); + } m_committedToMine = true; } @@ -967,13 +966,13 @@ bool State::sealBlock(bytesConstRef _header) ret.appendRaw(m_currentUncles); ret.swapOut(m_currentBytes); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData); - cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; + cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash() << ")"; // TODO: move into Sealer StructuredLogger::minedNewBlock( m_currentBlock.hash().abridged(), "", // Can't give the nonce here. "", //TODO: chain head hash here ?? - m_currentBlock.parentHash.abridged() + m_currentBlock.parentHash().abridged() ); // Quickly reset the transactions. @@ -1270,7 +1269,7 @@ State State::fromPending(unsigned _i) const ret.m_cache.clear(); _i = min(_i, m_transactions.size()); if (!_i) - ret.m_state.setRoot(m_previousBlock.stateRoot); + ret.m_state.setRoot(m_previousBlock.stateRoot()); else ret.m_state.setRoot(m_receipts[_i - 1].stateRoot()); while (ret.m_transactions.size() > _i) @@ -1287,10 +1286,10 @@ void State::applyRewards(vector const& _uncleBlockHeaders) u256 r = m_blockReward; for (auto const& i: _uncleBlockHeaders) { - addBalance(i.coinbaseAddress, m_blockReward * (8 + i.number - m_currentBlock.number) / 8); + addBalance(i.coinbaseAddress(), m_blockReward * (8 + i.number() - m_currentBlock.number()) / 8); r += m_blockReward / 32; } - addBalance(m_currentBlock.coinbaseAddress, r); + addBalance(m_currentBlock.coinbaseAddress(), r); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) diff --git a/libethereum/State.h b/libethereum/State.h index 805215ee5..e2bda6f24 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. - u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } + u256 gasLimitRemaining() const { return m_currentBlock.gasLimit() - gasUsed(); } /// Check if the address is in use. bool addressInUse(Address _address) const; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 94c8e2fef..a5c45af26 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -83,7 +83,7 @@ struct LocalisedLogEntry: public LogEntry ): LogEntry(_le), blockHash(_bi.hash()), - blockNumber((BlockNumber)_bi.number), + blockNumber((BlockNumber)_bi.number()), transactionHash(_th), transactionIndex(_ti), logIndex(_li), @@ -205,7 +205,7 @@ public: virtual void revert() {} /// Hash of a block if within the last 256 blocks, or h256() otherwise. - h256 blockhash(u256 _number) { return _number < currentBlock.number && _number >= (std::max(256, currentBlock.number) - 256) ? lastHashes[(unsigned)(currentBlock.number - 1 - _number)] : h256(); } + h256 blockhash(u256 _number) { return _number < currentBlock.number() && _number >= (std::max(256, currentBlock.number()) - 256) ? lastHashes[(unsigned)(currentBlock.number() - 1 - _number)] : h256(); } /// Get the code at the given location in code ROM. byte getCode(u256 _n) const { return _n < code.size() ? code[(size_t)_n] : 0; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 2b2ada0ae..f95481c54 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -400,19 +400,19 @@ bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) m_stack.back() = (u256)_ext.blockhash(m_stack.back()); break; case Instruction::COINBASE: - m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress); + m_stack.push_back((u160)_ext.currentBlock.coinbaseAddress()); break; case Instruction::TIMESTAMP: - m_stack.push_back(_ext.currentBlock.timestamp); + m_stack.push_back(_ext.currentBlock.timestamp()); break; case Instruction::NUMBER: - m_stack.push_back(_ext.currentBlock.number); + m_stack.push_back(_ext.currentBlock.number()); break; case Instruction::DIFFICULTY: - m_stack.push_back(_ext.currentBlock.difficulty); + m_stack.push_back(_ext.currentBlock.difficulty()); break; case Instruction::GASLIMIT: - m_stack.push_back(_ext.currentBlock.gasLimit); + m_stack.push_back(_ext.currentBlock.gasLimit()); break; case Instruction::PUSH1: case Instruction::PUSH2: diff --git a/libtestutils/BlockChainLoader.cpp b/libtestutils/BlockChainLoader.cpp index e6c47e2fe..7e08243af 100644 --- a/libtestutils/BlockChainLoader.cpp +++ b/libtestutils/BlockChainLoader.cpp @@ -36,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) // load genesisBlock m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); - assert(m_state.rootHash() == m_bc->info().stateRoot); + assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks for (auto const& block: _json["blocks"]) diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index 15d39bded..fae12708c 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -88,18 +88,18 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) if (_bi) { res["hash"] = toJS(_bi.hash()); - res["parentHash"] = toJS(_bi.parentHash); - res["sha3Uncles"] = toJS(_bi.sha3Uncles); - res["miner"] = toJS(_bi.coinbaseAddress); - res["stateRoot"] = toJS(_bi.stateRoot); - res["transactionsRoot"] = toJS(_bi.transactionsRoot); + res["parentHash"] = toJS(_bi.parentHash()); + res["sha3Uncles"] = toJS(_bi.sha3Uncles()); + res["miner"] = toJS(_bi.coinbaseAddress()); + res["stateRoot"] = toJS(_bi.stateRoot()); + res["transactionsRoot"] = toJS(_bi.transactionsRoot()); res["difficulty"] = toJS(_bi.difficulty); - res["number"] = toJS(_bi.number); + res["number"] = toJS(_bi.number()); res["gasUsed"] = toJS(_bi.gasUsed); res["gasLimit"] = toJS(_bi.gasLimit); - res["timestamp"] = toJS(_bi.timestamp); - res["extraData"] = toJS(_bi.extraData); - res["logsBloom"] = toJS(_bi.logBloom); + res["timestamp"] = toJS(_bi.timestamp()); + res["extraData"] = toJS(_bi.extraData()); + res["logsBloom"] = toJS(_bi.logBloom()); res["target"] = toJS(_bi.boundary()); // TODO: move into ProofOfWork. @@ -140,7 +140,7 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi, BlockDetails const& _bd, Uncl res["uncles"].append(toJS(h)); res["transactions"] = Json::Value(Json::arrayValue); for (unsigned i = 0; i < _ts.size(); i++) - res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number)); + res["transactions"].append(toJson(_ts[i], std::make_pair(_bi.hash(), i), (BlockNumber)_bi.number())); } return res; } @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()); + res["stateRoot"] = toJS(_t.stateRoot()()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index b43c4db51..bae980a7e 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -151,12 +151,12 @@ void ImportTest::importEnv(json_spirit::mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - m_environment.currentBlock.parentHash = h256(_o["previousHash"].get_str()); + m_environment.currentBlock.parentHash() = h256(_o["previousHash"].get_str()); m_environment.currentBlock.number = toInt(_o["currentNumber"]); m_environment.currentBlock.gasLimit = toInt(_o["currentGasLimit"]); m_environment.currentBlock.difficulty = toInt(_o["currentDifficulty"]); - m_environment.currentBlock.timestamp = toInt(_o["currentTimestamp"]); - m_environment.currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + m_environment.currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + m_environment.currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); m_statePre.m_previousBlock = m_environment.previousBlock; m_statePre.m_currentBlock = m_environment.currentBlock; diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 9ee93779e..7dbc5c91e 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -117,14 +117,14 @@ BOOST_AUTO_TEST_CASE(blocks) u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString()); h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString())); h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); - ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom); - ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress); + ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); + ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), - _blockInfo.extraData.begin(), - _blockInfo.extraData.end() + _blockInfo.extraData().begin(), + _blockInfo.extraData().end() ); ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); @@ -132,11 +132,11 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); - ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp); - ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot); - ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles); + ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); + ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; BlockInfo blockInfo = _client.blockInfo(blockHash); diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 20f60618f..cf44dfd9f 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -66,7 +66,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TBOOST_REQUIRE(o.count("pre")); ImportTest importer(o["pre"].get_obj()); TransientDirectory td_stateDB_tmp; - State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); //Imported blocks from the start std::vector blockSets; @@ -76,9 +76,9 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) trueState.commit(); if (_fillin) - biGenesisBlock.stateRoot = trueState.rootHash(); + biGenesisBlock.stateRoot() = trueState.rootHash(); else - TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot == trueState.rootHash()), "root hash does not match"); + TBOOST_CHECK_MESSAGE((biGenesisBlock.stateRoot() == trueState.rootHash()), "root hash does not match"); if (_fillin) { @@ -125,7 +125,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) TransientDirectory td_stateDB, td_bc; BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); - State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), state); state.commit(); @@ -225,7 +225,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (vBiUncles.size()) { // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + current_BlockHeader.sha3Uncles() = sha3(uncleStream.out()); updatePoW(current_BlockHeader); } @@ -302,7 +302,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) if (o.count("expect") > 0) { stateOptionsMap expectStateMap; - State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); o.erase(o.find("expect")); @@ -313,7 +313,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) o["lastblockhash"] = toString(trueBc.info().hash()); //make all values hex in pre section - State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); + State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress()); importer.importState(o["pre"].get_obj(), prestate); o["pre"] = fillJsonWithState(prestate); }//_fillin @@ -374,19 +374,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { //Check the fields restored from RLP to original fields TBOOST_CHECK_MESSAGE((blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce)), "hash in given RLP not matching the block hash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash == blockFromRlp.parentHash), "parentHash in given RLP not matching the block parentHash!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles == blockFromRlp.sha3Uncles), "sha3Uncles in given RLP not matching the block sha3Uncles!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress == blockFromRlp.coinbaseAddress),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot == blockFromRlp.stateRoot), "stateRoot in given RLP not matching the block stateRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot == blockFromRlp.transactionsRoot), "transactionsRoot in given RLP not matching the block transactionsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot == blockFromRlp.receiptsRoot), "receiptsRoot in given RLP not matching the block receiptsRoot!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom == blockFromRlp.logBloom), "logBloom in given RLP not matching the block logBloom!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.parentHash() == blockFromRlp.parentHash()), "parentHash in given RLP not matching the block parentHash!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.sha3Uncles() == blockFromRlp.sha3Uncles()), "sha3Uncles in given RLP not matching the block sha3Uncles!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.coinbaseAddress() == blockFromRlp.coinbaseAddress()),"coinbaseAddress in given RLP not matching the block coinbaseAddress!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.stateRoot() == blockFromRlp.stateRoot()), "stateRoot in given RLP not matching the block stateRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.transactionsRoot() == blockFromRlp.transactionsRoot()), "transactionsRoot in given RLP not matching the block transactionsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.receiptsRoot() == blockFromRlp.receiptsRoot()), "receiptsRoot in given RLP not matching the block receiptsRoot!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.logBloom() == blockFromRlp.logBloom()), "logBloom in given RLP not matching the block logBloom!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.difficulty == blockFromRlp.difficulty), "difficulty in given RLP not matching the block difficulty!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.number == blockFromRlp.number), "number in given RLP not matching the block number!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasLimit == blockFromRlp.gasLimit),"gasLimit in given RLP not matching the block gasLimit!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.gasUsed == blockFromRlp.gasUsed), "gasUsed in given RLP not matching the block gasUsed!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp == blockFromRlp.timestamp), "timestamp in given RLP not matching the block timestamp!"); - TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData == blockFromRlp.extraData), "extraData in given RLP not matching the block extraData!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.timestamp() == blockFromRlp.timestamp()), "timestamp in given RLP not matching the block timestamp!"); + TBOOST_CHECK_MESSAGE((blockHeaderFromFields.extraData() == blockFromRlp.extraData()), "extraData in given RLP not matching the block extraData!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.mixHash == blockFromRlp.mixHash), "mixHash in given RLP not matching the block mixHash!"); TBOOST_CHECK_MESSAGE((blockHeaderFromFields.nonce == blockFromRlp.nonce), "nonce in given RLP not matching the block nonce!"); @@ -551,7 +551,7 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector BlockInfo uncleBlockFromFields = constructBlock(uncleHeaderObj); // make uncle header valid - uncleBlockFromFields.timestamp = (u256)time(0); + uncleBlockFromFields.timestamp() = (u256)time(0); cnote << "uncle block n = " << toString(uncleBlockFromFields.number); if (_vBiBlocks.size() > 2) { @@ -568,15 +568,15 @@ mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector uncleBlockFromFields.difficulty = overwrite == "difficulty" ? toInt(uncleHeaderObj["difficulty"]) : uncleBlockFromFields.difficulty; uncleBlockFromFields.gasLimit = overwrite == "gasLimit" ? toInt(uncleHeaderObj["gasLimit"]) : uncleBlockFromFields.gasLimit; uncleBlockFromFields.gasUsed = overwrite == "gasUsed" ? toInt(uncleHeaderObj["gasUsed"]) : uncleBlockFromFields.gasUsed; - uncleBlockFromFields.parentHash = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash; - uncleBlockFromFields.stateRoot = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot; + uncleBlockFromFields.parentHash() = overwrite == "parentHash" ? h256(uncleHeaderObj["parentHash"].get_str()) : uncleBlockFromFields.parentHash(); + uncleBlockFromFields.stateRoot() = overwrite == "stateRoot" ? h256(uncleHeaderObj["stateRoot"].get_str()) : uncleBlockFromFields.stateRoot(); if (overwrite == "parentHashIsBlocksParent") uncleBlockFromFields.populateFromParent(_vBiBlocks[_vBiBlocks.size() - 1]); if (overwrite == "timestamp") { - uncleBlockFromFields.timestamp = toInt(uncleHeaderObj["timestamp"]); + uncleBlockFromFields.timestamp() = toInt(uncleHeaderObj["timestamp"]); uncleBlockFromFields.difficulty = uncleBlockFromFields.calculateDifficulty(_vBiBlocks[(size_t)uncleBlockFromFields.number - 1]); } } @@ -660,19 +660,19 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) { BlockInfo tmp = _header; if (ho.count("parentHash")) - tmp.parentHash = h256(ho["parentHash"].get_str()); + tmp.parentHash() = h256(ho["parentHash"].get_str()); if (ho.count("uncleHash")) - tmp.sha3Uncles = h256(ho["uncleHash"].get_str()); + tmp.sha3Uncles() = h256(ho["uncleHash"].get_str()); if (ho.count("coinbase")) - tmp.coinbaseAddress = Address(ho["coinbase"].get_str()); + tmp.coinbaseAddress() = Address(ho["coinbase"].get_str()); if (ho.count("stateRoot")) - tmp.stateRoot = h256(ho["stateRoot"].get_str()); + tmp.stateRoot() = h256(ho["stateRoot"].get_str()); if (ho.count("transactionsTrie")) - tmp.transactionsRoot = h256(ho["transactionsTrie"].get_str()); + tmp.transactionsRoot() = h256(ho["transactionsTrie"].get_str()); if (ho.count("receiptTrie")) - tmp.receiptsRoot = h256(ho["receiptTrie"].get_str()); + tmp.receiptsRoot() = h256(ho["receiptTrie"].get_str()); if (ho.count("bloom")) - tmp.logBloom = LogBloom(ho["bloom"].get_str()); + tmp.logBloom() = LogBloom(ho["bloom"].get_str()); if (ho.count("difficulty")) tmp.difficulty = toInt(ho["difficulty"]); if (ho.count("number")) @@ -682,9 +682,9 @@ void overwriteBlockHeader(BlockInfo& _header, mObject& _blObj) if (ho.count("gasUsed")) tmp.gasUsed = toInt(ho["gasUsed"]); if (ho.count("timestamp")) - tmp.timestamp = toInt(ho["timestamp"]); + tmp.timestamp() = toInt(ho["timestamp"]); if (ho.count("extraData")) - tmp.extraData = importByteArray(ho["extraData"].get_str()); + tmp.extraData() = importByteArray(ho["extraData"].get_str()); // find new valid nonce if (tmp != _header && tmp.difficulty) @@ -751,19 +751,19 @@ mArray writeTransactionsToJson(Transactions const& txs) mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) { - _o["parentHash"] = toString(_bi.parentHash); - _o["uncleHash"] = toString(_bi.sha3Uncles); - _o["coinbase"] = toString(_bi.coinbaseAddress); - _o["stateRoot"] = toString(_bi.stateRoot); - _o["transactionsTrie"] = toString(_bi.transactionsRoot); - _o["receiptTrie"] = toString(_bi.receiptsRoot); - _o["bloom"] = toString(_bi.logBloom); + _o["parentHash"] = toString(_bi.parentHash()); + _o["uncleHash"] = toString(_bi.sha3Uncles()); + _o["coinbase"] = toString(_bi.coinbaseAddress()); + _o["stateRoot"] = toString(_bi.stateRoot()); + _o["transactionsTrie"] = toString(_bi.transactionsRoot()); + _o["receiptTrie"] = toString(_bi.receiptsRoot()); + _o["bloom"] = toString(_bi.logBloom()); _o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); - _o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); + _o["number"] = toCompactHex(_bi.number(), HexPrefix::Add, 1); _o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); _o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); - _o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); - _o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); + _o["timestamp"] = toCompactHex(_bi.timestamp(), HexPrefix::Add, 1); + _o["extraData"] = toHex(_bi.extraData(), 2, HexPrefix::Add); _o["mixHash"] = toString(_bi.mixHash); _o["nonce"] = toString(_bi.nonce); _o["hash"] = toString(_bi.hash()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 02ff4517a..2d5a2faa6 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot, h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index fdfb180fb..28b2e43ab 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -83,10 +83,10 @@ void FakeExtVM::reset(u256 _myBalance, u256 _myNonce, map const& _st mObject FakeExtVM::exportEnv() { mObject ret; - ret["previousHash"] = toString(currentBlock.parentHash); + ret["previousHash"] = toString(currentBlock.parentHash()); ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); - ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp, HexPrefix::Add, 1); - ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress); + ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); + ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); return ret; @@ -102,13 +102,13 @@ void FakeExtVM::importEnv(mObject& _o) assert(_o.count("currentCoinbase") > 0); assert(_o.count("currentNumber") > 0); - currentBlock.parentHash = h256(_o["previousHash"].get_str()); + currentBlock.parentHash() = h256(_o["previousHash"].get_str()); currentBlock.number = toInt(_o["currentNumber"]); lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp = toInt(_o["currentTimestamp"]); - currentBlock.coinbaseAddress = Address(_o["currentCoinbase"].get_str()); + currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); } mObject FakeExtVM::exportState() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 9f806347e..be44ea009 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1187,7 +1187,7 @@ BOOST_AUTO_TEST_CASE(now) { char const* sourceCode = "contract test {\n" " function someInfo() returns (bool success) {\n" - " return block.timestamp == now && now > 0;\n" + " return block.timestamp() == now && now > 0;\n" " }\n" "}\n"; compileAndRun(sourceCode); diff --git a/third/MainWin.cpp b/third/MainWin.cpp index f2a90cc0b..a3b05572f 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl; From f663801126fd23efd838fe88e66571384950e56e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 16 Jul 2015 01:34:11 +0200 Subject: [PATCH 18/22] Minor fix. --- libethereum/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ec37302a2..357926d03 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -98,7 +98,7 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); if (_forceAction == WithExisting::Rescue) - m_bc.rescue(m_stateDB); + bc().rescue(m_stateDB); m_gp->update(bc()); From ef0d9a96fb18ae8efb3bb84d775dcd73f49c4c4a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 11:43:23 +0200 Subject: [PATCH 19/22] fixed build --- evmjit/libevmjit-cpp/JitVM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 4e1fb66ea..d96da87c1 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -23,8 +23,8 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); - rejected |= _ext.currentBlock.number > std::numeric_limits::max(); - rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.number() > std::numeric_limits::max(); + rejected |= _ext.currentBlock.timestamp() > std::numeric_limits::max(); if (rejected) { @@ -42,10 +42,10 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.origin = eth2jit(fromAddress(_ext.origin)); m_data.callValue = eth2jit(_ext.value); m_data.coinBase = eth2jit(fromAddress(_ext.currentBlock.coinbaseAddress())); - m_data.difficulty = eth2jit(_ext.currentBlock.difficulty); - m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit); - m_data.number = static_cast(_ext.currentBlock.number); - m_data.timestamp() = static_cast(_ext.currentBlock.timestamp()); + m_data.difficulty = eth2jit(_ext.currentBlock.difficulty()); + m_data.gasLimit = eth2jit(_ext.currentBlock.gasLimit()); + m_data.number = static_cast(_ext.currentBlock.number()); + m_data.timestamp = static_cast(_ext.currentBlock.timestamp()); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); m_data.codeHash = eth2jit(_ext.codeHash); From e6d2200ccacb16997eb855b8d84a62c0fdc2246a Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 16:45:23 +0200 Subject: [PATCH 20/22] mix working --- CMakeLists.txt | 28 +++++++------- alethzero/MainWin.cpp | 53 ++++++++++++++------------- alethzero/MiningView.cpp | 4 +- alethzero/MiningView.h | 4 +- exp/CMakeLists.txt | 4 +- libethereum/BlockChain.cpp | 1 - libtestutils/BlockChainLoader.cpp | 3 +- libtestutils/StateLoader.cpp | 2 +- libtestutils/StateLoader.h | 2 + libweb3jsonrpc/JsonHelper.cpp | 8 ++-- libweb3jsonrpc/WebThreeStubServer.cpp | 2 +- libweb3jsonrpc/WebThreeStubServer.h | 4 +- libwebthree/WebThree.cpp | 2 +- mix/ClientModel.cpp | 4 +- mix/MixClient.cpp | 36 +++++++++--------- mix/MixClient.h | 36 +++++++++++++++--- 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 421dd1bb7..271f3ed65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,13 +400,13 @@ if (TOOLS) endif () if (JSONRPC AND GENERAL) -# add_subdirectory(libweb3jsonrpc) + add_subdirectory(libweb3jsonrpc) endif () if (JSCONSOLE) -# add_subdirectory(libjsengine) -# add_subdirectory(libjsconsole) -# add_subdirectory(ethconsole) + add_subdirectory(libjsengine) + add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () if (NOT WIN32) @@ -434,31 +434,31 @@ add_subdirectory(libethcore) if (GENERAL) add_subdirectory(libevm) add_subdirectory(libethereum) -# add_subdirectory(libwebthree) + add_subdirectory(libwebthree) endif () if (MINER OR TOOLS) -# add_subdirectory(ethminer) + add_subdirectory(ethminer) endif () if (ETHKEY OR TOOLS) -# add_subdirectory(ethkey) + add_subdirectory(ethkey) endif () if (TESTS) -# add_subdirectory(libtestutils) -# add_subdirectory(test) + add_subdirectory(libtestutils) + add_subdirectory(test) if (JSONRPC) -# add_subdirectory(ethrpctest) + add_subdirectory(ethrpctest) endif () endif () if (TOOLS) -# add_subdirectory(rlp) -# add_subdirectory(abi) -# add_subdirectory(ethvm) -# add_subdirectory(eth) + add_subdirectory(rlp) + add_subdirectory(abi) + add_subdirectory(ethvm) + add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") add_subdirectory(exp) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index ad8f5528c..181772ddb 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -189,9 +189,9 @@ Main::Main(QWidget *parent) : #endif m_servers.append(QString::fromStdString(Host::pocHost() + ":30303")); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; - auto block = CanonBlockChain::createGenesisBlock(); - cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot() << endl; + auto block = CanonBlockChain::createGenesisBlock(); + cerr << "Block Hash: " << CanonBlockChain::genesis().hash() << endl; cerr << "Block RLP: " << RLP(block) << endl; cerr << "Block Hex: " << toHex(block) << endl; cerr << "eth Network protocol version: " << eth::c_protocolVersion << endl; @@ -208,13 +208,14 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); - ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); QSettings s("ethereum", "alethzero"); m_networkConfig = s.value("peers").toByteArray(); bytesConstRef network((byte*)m_networkConfig.data(), m_networkConfig.size()); m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); + ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version)); + m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); m_server.reset(w3ss); @@ -1124,7 +1125,7 @@ void Main::refreshMining() QString t; if (gp.first != EthashAux::NotGenerating) t = QString("DAG for #%1-#%2: %3% complete; ").arg(gp.first).arg(gp.first + ETHASH_EPOCH_LENGTH - 1).arg(gp.second); - MiningProgress p = ethereum()->miningProgress(); + WorkingProgress p = ethereum()->miningProgress(); ui->mineStatus->setText(t + (ethereum()->isMining() ? p.hashes > 0 ? QString("%1s @ %2kH/s").arg(p.ms / 1000).arg(p.ms ? p.hashes / p.ms : 0) : "Awaiting DAG" : "Not mining")); if (ethereum()->isMining() && p.hashes > 0) { @@ -1629,7 +1630,7 @@ void Main::on_transactionQueue_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; @@ -1699,7 +1700,7 @@ void Main::on_blocks_currentItemChanged() auto details = ethereum()->blockChain().details(h); auto blockData = ethereum()->blockChain().block(h); auto block = RLP(blockData); - BlockInfo info(blockData); + Ethash::BlockHeader info(blockData); stringstream s; @@ -1709,21 +1710,21 @@ void Main::on_blocks_currentItemChanged() time_t rawTime = (time_t)(uint64_t)info.timestamp(); strftime(timestamp, 64, "%c", localtime(&rawTime)); s << "

" << h << "

"; - s << "

#" << info.number; + s << "

#" << info.number(); s << "   " << timestamp << "

"; - s << "
D/TD: " << info.difficulty << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty) << "/2^" << log2((double)details.totalDifficulty) << "
"; + s << "
D/TD: " << info.difficulty() << "/" << details.totalDifficulty << " = 2^" << log2((double)info.difficulty()) << "/2^" << log2((double)details.totalDifficulty) << "
"; s << "   Children: " << details.children.size() << ""; - s << "
Gas used/limit: " << info.gasUsed << "/" << info.gasLimit << "" << "
"; + s << "
Gas used/limit: " << info.gasUsed() << "/" << info.gasLimit() << "" << "
"; s << "
Beneficiary: " << htmlEscaped(pretty(info.coinbaseAddress())) << " " << info.coinbaseAddress() << "" << "
"; s << "
Seed hash: " << info.seedHash() << "" << "
"; - s << "
Mix hash: " << info.mixHash << "" << "
"; - s << "
Nonce: " << info.nonce << "" << "
"; - s << "
Hash w/o nonce: " << info.headerHash(WithoutProof) << "" << "
"; - s << "
Difficulty: " << info.difficulty << "" << "
"; - if (info.number) + s << "
Mix hash: " << info.mixHash() << "" << "
"; + s << "
Nonce: " << info.nonce() << "" << "
"; + s << "
Hash w/o nonce: " << info.hashWithout() << "" << "
"; + s << "
Difficulty: " << info.difficulty() << "" << "
"; + if (info.number()) { - auto e = EthashAux::eval(info); - s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; + auto e = EthashAux::eval(info.seedHash(), info.hashWithout(), info.nonce()); + s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << "
"; s << "
Parent: " << info.parentHash() << "" << "
"; } else @@ -1740,19 +1741,19 @@ void Main::on_blocks_currentItemChanged() s << "
Uncles: " << block[2].itemCount() << " @" << info.sha3Uncles() << "" << "
"; for (auto u: block[2]) { - BlockInfo uncle = BlockInfo::fromHeader(u.data()); + Ethash::BlockHeader uncle(u.data(), CheckNothing, h256(), HeaderData); char const* line = "
 "; s << line << "Hash: " << uncle.hash() << "" << "
"; s << line << "Parent: " << uncle.parentHash() << "" << ""; - s << line << "Number: " << uncle.number << "" << ""; + s << line << "Number: " << uncle.number() << "" << ""; s << line << "Coinbase: " << htmlEscaped(pretty(uncle.coinbaseAddress())) << " " << uncle.coinbaseAddress() << "" << ""; s << line << "Seed hash: " << uncle.seedHash() << "" << ""; - s << line << "Mix hash: " << uncle.mixHash << "" << ""; - s << line << "Nonce: " << uncle.nonce << "" << ""; + s << line << "Mix hash: " << uncle.mixHash() << "" << ""; + s << line << "Nonce: " << uncle.nonce() << "" << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutProof) << "" << ""; - s << line << "Difficulty: " << uncle.difficulty << "" << ""; - auto e = EthashAux::eval(uncle); - s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; + s << line << "Difficulty: " << uncle.difficulty() << "" << ""; + auto e = EthashAux::eval(uncle.seedHash(), uncle.hashWithout(), uncle.nonce()); + s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty()) << " (mixhash: " << e.mixHash.abridged() << ")" << ""; } if (info.parentHash()) s << "
Pre: " << BlockInfo(ethereum()->blockChain().block(info.parentHash())).stateRoot() << "" << "
"; @@ -1764,7 +1765,7 @@ void Main::on_blocks_currentItemChanged() unsigned ii = 0; for (auto const& i: block[1]) { - s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot()() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; + s << "
" << sha3(i.data()).abridged() << ": " << receipts.receipts[ii].stateRoot() << " [" << receipts.receipts[ii].gasUsed() << " used]" << "
"; ++ii; } s << "
Post: " << info.stateRoot() << "" << "
"; @@ -1807,7 +1808,7 @@ void Main::on_blocks_currentItemChanged() else s << "
Log Bloom: Uneventful
"; s << "
Gas Used: " << receipt.gasUsed() << "
"; - s << "
End State: " << receipt.stateRoot()().abridged() << "
"; + s << "
End State: " << receipt.stateRoot().abridged() << "
"; auto r = receipt.rlp(); s << "
Receipt: " << toString(RLP(r)) << "
"; s << "
Receipt-Hex: " Span(Mono) << toHex(receipt.rlp()) << "
"; diff --git a/alethzero/MiningView.cpp b/alethzero/MiningView.cpp index e020408ea..fb9de0346 100644 --- a/alethzero/MiningView.cpp +++ b/alethzero/MiningView.cpp @@ -36,7 +36,7 @@ using namespace dev::eth; // types using dev::eth::MineInfo; -using dev::eth::MiningProgress; +using dev::eth::WorkingProgress; // functions using dev::toString; @@ -50,7 +50,7 @@ MiningView::MiningView(QWidget* _p): QWidget(_p) { } -void MiningView::appendStats(list const& _i, MiningProgress const& _p) +void MiningView::appendStats(list const& _i, WorkingProgress const& _p) { (void)_p; if (_i.empty()) diff --git a/alethzero/MiningView.h b/alethzero/MiningView.h index 65b9f2ec9..ae81a7cc4 100644 --- a/alethzero/MiningView.h +++ b/alethzero/MiningView.h @@ -42,14 +42,14 @@ class MiningView: public QWidget public: MiningView(QWidget* _p = nullptr); - void appendStats(std::list const& _l, dev::eth::MiningProgress const& _p); + void appendStats(std::list const& _l, dev::eth::WorkingProgress const& _p); void resetStats(); protected: virtual void paintEvent(QPaintEvent*); private: - dev::eth::MiningProgress m_progress; + dev::eth::WorkingProgress m_progress; unsigned m_duration = 300; std::vector m_values; std::vector m_bests; diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index b9f477385..0e19ac84d 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -21,10 +21,10 @@ if (READLINE_FOUND) endif() if (JSONRPC) -# target_link_libraries(${EXECUTABLE} web3jsonrpc) + target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() -#target_link_libraries(${EXECUTABLE} webthree) +target_link_libraries(${EXECUTABLE} webthree) target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} p2p) if (ETHASHCL) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b696c77bd..03ab1b46a 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -137,7 +137,6 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map #include "BlockChainLoader.h" #include "StateLoader.h" #include "Common.h" @@ -35,7 +36,7 @@ BlockChainLoader::BlockChainLoader(Json::Value const& _json) m_state = sl.state(); // load genesisBlock - m_bc.reset(new BlockChain(fromHex(_json["genesisRLP"].asString()), m_dir.path(), WithExisting::Kill)); + m_bc.reset(new FullBlockChain(fromHex(_json["genesisRLP"].asString()), sl.stateDefinition(), m_dir.path(), WithExisting::Kill)); assert(m_state.rootHash() == m_bc->info().stateRoot()); // load blocks diff --git a/libtestutils/StateLoader.cpp b/libtestutils/StateLoader.cpp index 235f1c573..cd5c37e96 100644 --- a/libtestutils/StateLoader.cpp +++ b/libtestutils/StateLoader.cpp @@ -27,7 +27,7 @@ using namespace dev::eth; using namespace dev::test; StateLoader::StateLoader(Json::Value const& _json, std::string const& _dbPath): - m_state(State::openDB(_dbPath, WithExisting::Kill), BaseState::Empty) + m_state(State::openDB(_dbPath, h256{}, WithExisting::Kill), BaseState::Empty) { for (string const& name: _json.getMemberNames()) { diff --git a/libtestutils/StateLoader.h b/libtestutils/StateLoader.h index 47eb26900..c66f53148 100644 --- a/libtestutils/StateLoader.h +++ b/libtestutils/StateLoader.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace dev { @@ -38,6 +39,7 @@ class StateLoader public: StateLoader(Json::Value const& _json, std::string const& _dbPath); eth::State const& state() const { return m_state; } + eth::StateDefinition const& stateDefinition() const { return m_state.m_cache; } private: eth::State m_state; diff --git a/libweb3jsonrpc/JsonHelper.cpp b/libweb3jsonrpc/JsonHelper.cpp index fae12708c..54fde52e8 100644 --- a/libweb3jsonrpc/JsonHelper.cpp +++ b/libweb3jsonrpc/JsonHelper.cpp @@ -93,10 +93,10 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi) res["miner"] = toJS(_bi.coinbaseAddress()); res["stateRoot"] = toJS(_bi.stateRoot()); res["transactionsRoot"] = toJS(_bi.transactionsRoot()); - res["difficulty"] = toJS(_bi.difficulty); + res["difficulty"] = toJS(_bi.difficulty()); res["number"] = toJS(_bi.number()); - res["gasUsed"] = toJS(_bi.gasUsed); - res["gasLimit"] = toJS(_bi.gasLimit); + res["gasUsed"] = toJS(_bi.gasUsed()); + res["gasLimit"] = toJS(_bi.gasLimit()); res["timestamp"] = toJS(_bi.timestamp()); res["extraData"] = toJS(_bi.extraData()); res["logsBloom"] = toJS(_bi.logBloom()); @@ -176,7 +176,7 @@ Json::Value toJson(dev::eth::TransactionSkeleton const& _t) Json::Value toJson(dev::eth::TransactionReceipt const& _t) { Json::Value res; - res["stateRoot"] = toJS(_t.stateRoot()()); + res["stateRoot"] = toJS(_t.stateRoot()); res["gasUsed"] = toJS(_t.gasUsed()); res["bloom"] = toJS(_t.bloom()); res["log"] = dev::toJson(_t.log()); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 3aff9cf23..bf49d3322 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -106,7 +106,7 @@ bool WebThreeStubServer::admin_eth_setBidPrice(std::string const& _wei, std::str return true; } -dev::eth::CanonBlockChain const& WebThreeStubServer::bc() const +dev::eth::BlockChain const& WebThreeStubServer::bc() const { return m_web3.ethereum()->blockChain(); } diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4d545c90e..2860f852b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -34,7 +34,7 @@ namespace eth { class KeyManager; class TrivialGasPricer; -class CanonBlockChain; +class BlockChain; class BlockQueue; } @@ -89,7 +89,7 @@ private: private: h256 blockHash(std::string const& _blockNumberOrHash) const; - dev::eth::CanonBlockChain const& bc() const; + dev::eth::BlockChain const& bc() const; dev::eth::BlockQueue const& bq() const; dev::WebThreeDirect& m_web3; diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index 3c1dea40f..7889b5935 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -52,7 +52,7 @@ WebThreeDirect::WebThreeDirect( Defaults::setDBPath(_dbPath); if (_interfaces.count("eth")) { - m_ethereum.reset(new eth::Client(&m_net, _dbPath, _we, 0)); + m_ethereum.reset(new eth::EthashClient(&m_net, shared_ptr(), _dbPath, _we, 0)); m_ethereum->setExtraData(rlpList(0, _clientVersion, m_net.id())); } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 90ff19feb..5c5f2f4cd 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -686,9 +686,9 @@ RecordLogEntry* ClientModel::lastBlock() const { eth::BlockInfo blockInfo = m_client->blockInfo(); stringstream strGas; - strGas << blockInfo.gasUsed; + strGas << blockInfo.gasUsed(); stringstream strNumber; - strNumber << blockInfo.number; + strNumber << blockInfo.number(); RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index ea4686601..eef6ad6ec 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -24,12 +24,13 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include #include "Exceptions.h" using namespace std; @@ -45,22 +46,20 @@ u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix someho namespace { +} -struct MixPow //dummy POW +MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot): + FullBlockChain(createGenesisBlock(_stateRoot), std::unordered_map(), _path, WithExisting::Kill) { - typedef int Solution; - static bool verify(BlockInfo const&) { return true; } -}; - } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { RLPStream block(3); - block.appendList(15) + block.appendList(13) << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); + << std::string(); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); @@ -78,7 +77,6 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); Guard fl(x_filtersWatches); @@ -91,12 +89,13 @@ void MixClient::resetState(std::unordered_map const& _accounts SecureTrieDB accountState(&m_stateDB); accountState.init(); - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + dev::eth::commit(_accounts, accountState); h256 stateRoot = accountState.root(); m_bc.reset(); m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); + State s(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + s.sync(bc()); + m_state = s; m_startState = m_state; WriteGuard lx(x_executions); m_executions.clear(); @@ -275,11 +274,14 @@ void MixClient::mine() { WriteGuard l(x_state); m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + + NoProof::BlockHeader h(m_state.info()); + RLPStream header; + h.streamRLP(header); + m_state.sealBlock(header.out()); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; } ExecutionResult MixClient::lastExecution() const @@ -383,9 +385,9 @@ uint64_t MixClient::hashrate() const return 0; } -eth::MiningProgress MixClient::miningProgress() const +eth::WorkingProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::WorkingProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index f9574e90a..279692de5 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -32,13 +33,40 @@ namespace dev { + namespace mix { -class MixBlockChain: public dev::eth::BlockChain +class NoProof +{ + class BlockHeaderRaw: public dev::eth::BlockInfo + { + public: + static const unsigned SealFields = 0; + + protected: + BlockHeaderRaw() = default; + BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} + + void populateFromHeader(RLP const& _header, dev::eth::Strictness _s) { (void) _header; (void) _s; } + void populateFromParent(BlockHeaderRaw const& _parent) { (void)_parent; } + void streamRLPFields(RLPStream& _s) const { (void) _s; } + }; + +public: + + static std::string name() { return "NoProof"; } + static unsigned revision() { return 0; } + using BlockHeader = dev::eth::BlockHeaderPolished; + +private: + static AddressHash s_authorities; +}; + +class MixBlockChain: public dev::eth::FullBlockChain { public: - MixBlockChain(std::string const& _path, h256 _stateRoot): BlockChain(createGenesisBlock(_stateRoot), _path, WithExisting::Kill) {} + MixBlockChain(std::string const& _path, h256 _stateRoot); static bytes createGenesisBlock(h256 _stateRoot); }; @@ -67,9 +95,7 @@ public: void stopMining() override; bool isMining() const override; uint64_t hashrate() const override; - eth::MiningProgress miningProgress() const override; - eth::ProofOfWork::WorkPackage getWork() override { return eth::ProofOfWork::WorkPackage(); } - bool submitWork(eth::ProofOfWork::Solution const&) override { return false; } + eth::WorkingProgress miningProgress() const override; virtual void flushTransactions() override {} /// @returns the last mined block information From 1820dbdcfcee55569ef302450fbb0f210ec39437 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 18:11:08 +0200 Subject: [PATCH 21/22] started tests refactoring --- libethcore/Common.h | 3 ++- libethereum/BlockChain.cpp | 2 +- libethereum/BlockChain.h | 9 +++++---- libethereum/BlockQueue.cpp | 2 +- libethereum/Client.cpp | 3 +-- mix/MixClient.cpp | 2 +- test/TestHelper.cpp | 2 +- test/libethcore/dagger.cpp | 4 ++-- test/libethereum/ClientBase.cpp | 14 +++++++------- test/libethereum/genesis.cpp | 6 +++--- test/libethereum/stateOriginal.cpp | 5 +++-- 11 files changed, 27 insertions(+), 25 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 5c0a0cc79..116e1d5ed 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -130,9 +130,10 @@ struct ImportRequirements TransactionBasic = 8, ///< Check the basic structure of the transactions. UncleSeals = 16, ///< Check the basic structure of the uncles. TransactionSignatures = 32, ///< Check the basic structure of the transactions. + Parent = 64, ///< Check parent block header CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures - Default = ValidSeal | DontHave | CheckUncles | CheckTransactions, + Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent, None = 0 }; }; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 03ab1b46a..8a654fa51 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -355,7 +355,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number()), 500) - r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Everything & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; goodTransactions += r.goodTranactions; diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 3ff85c8a6..811da8609 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -118,12 +118,12 @@ public: /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default) noexcept; + std::pair attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept; /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. - ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -391,7 +391,8 @@ public: { BlockHeader h(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce); h.verifyInternals(_block); - h.verifyParent(header(h.parentHash())); + if ((_ir & ImportRequirements::Parent) != 0) + h.verifyParent(header(h.parentHash())); res.info = static_cast(h); } catch (Exception& ex) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c9ee4c1cf..d0ca34b1c 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -110,7 +110,7 @@ void BlockQueue::verifierBody() swap(work.block, res.blockData); try { - res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything); + res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent); } catch (...) { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 357926d03..d43f240b7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -84,10 +84,9 @@ void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _ // TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database // until after the construction. m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction); - m_preMine = State(m_stateDB); - m_postMine = State(m_stateDB); // LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block. m_preMine = bc().genesisState(m_stateDB); + m_postMine = m_preMine; m_bq.setChain(bc()); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index eef6ad6ec..67f2a2507 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -279,7 +279,7 @@ void MixClient::mine() RLPStream header; h.streamRLP(header); m_state.sealBlock(header.out()); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidSeal); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Everything & ~ImportRequirements::ValidSeal); m_state.sync(bc()); m_startState = m_state; } diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index bae980a7e..30f323369 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -63,7 +63,7 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; f.onSolutionFound([&](ProofOfWork::Solution sol) { diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 061b5ae79..8d4cba933 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -54,10 +54,10 @@ BOOST_AUTO_TEST_CASE(basic_test) cnote << i.first; js::mObject& o = i.second.get_obj(); vector> ss; - BlockInfo header = BlockInfo::fromHeader(fromHex(o["header"].get_str()), CheckNothing); + Ethash::BlockHeader header(fromHex(o["header"].get_str()), CheckNothing); h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); - BOOST_REQUIRE_EQUAL(headerHash, header.headerHash(WithoutNonce)); + BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); BOOST_REQUIRE_EQUAL(nonce, header.nonce); unsigned cacheSize(o["cache_size"].get_int()); diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index 7dbc5c91e..a426ff53f 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -119,21 +119,21 @@ BOOST_AUTO_TEST_CASE(blocks) h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString())); ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom()); ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress()); - ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty); + ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty()); ETH_CHECK_EQUAL_COLLECTIONS( expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(), _blockInfo.extraData().begin(), _blockInfo.extraData().end() ); - ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit); - ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed); + ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit()); + ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed()); ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash()); - ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash); - ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce); - ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number); + ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash()); + ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce()); + ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number()); ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash()); - ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo..receiptsRoot()); + ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp()); ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot()); ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); diff --git a/test/libethereum/genesis.cpp b/test/libethereum/genesis.cpp index 2d5a2faa6..39997572f 100644 --- a/test/libethereum/genesis.cpp +++ b/test/libethereum/genesis.cpp @@ -60,9 +60,9 @@ BOOST_AUTO_TEST_CASE(genesis_tests) js::mObject o = v.get_obj(); - BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); - BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); - BOOST_CHECK_EQUAL(BlockInfo::headerHash(CanonBlockChain::createGenesisBlock()), h256(o["genesis_hash"].get_str())); + BOOST_CHECK_EQUAL(CanonBlockChain::genesis().stateRoot(), h256(o["genesis_state_root"].get_str())); + BOOST_CHECK_EQUAL(toHex(CanonBlockChain::createGenesisBlock()), toHex(fromHex(o["genesis_rlp_hex"].get_str()))); + BOOST_CHECK_EQUAL(Ethash::BlockHeader(CanonBlockChain::createGenesisBlock()).hashWithout(), h256(o["genesis_hash"].get_str())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/stateOriginal.cpp b/test/libethereum/stateOriginal.cpp index e3f8ac29f..163c89e50 100644 --- a/test/libethereum/stateOriginal.cpp +++ b/test/libethereum/stateOriginal.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -59,8 +60,8 @@ BOOST_AUTO_TEST_CASE(Complex) Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count())); - OverlayDB stateDB = State::openDB(); - CanonBlockChain bc; + OverlayDB stateDB = State::openDB(h256()); + CanonBlockChain bc; cout << bc; State s = bc.genesisState(stateDB); From ad50498faeab276967ef469b43ffad227265c310 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 16 Jul 2015 20:53:58 +0200 Subject: [PATCH 22/22] eth working --- eth/main.cpp | 2 +- ethminer/MinerAux.h | 26 ++++++++++++-------------- libethcore/BlockInfo.h | 1 + libethereum/Client.h | 6 +++++- test/TestHelper.cpp | 17 ++++++++++++----- test/libethcore/dagger.cpp | 6 +++--- test/libethereum/ClientBase.cpp | 4 ++-- test/libethereum/gaspricer.cpp | 3 ++- test/libevm/vm.cpp | 10 +++++----- 9 files changed, 43 insertions(+), 32 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 8bbec9f00..4a8501a97 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1311,7 +1311,7 @@ int main(int argc, char** argv) { try { - CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); + CanonBlockChain::setGenesisNonce(Nonce(argv[++i])); } catch (...) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 0d227b1ef..01083012f 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -397,17 +397,16 @@ public: private: void doInitDAG(unsigned _n) { - BlockInfo bi; - bi.number() = _n; - cout << "Initializing DAG for epoch beginning #" << (bi.number() / 30000 * 30000) << " (seedhash " << bi.proofCache().abridged() << "). This will take a while." << endl; - Ethash::prep(bi); + h256 seedHash = EthashAux::seedHash(_n); + cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl; + EthashAux::full(seedHash, true); exit(0); } void doBenchmark(MinerType _m, bool _phoneHome, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5) { - BlockInfo genesis; - genesis.difficulty = 1 << 18; + Ethash::BlockHeader genesis; + genesis.setDifficulty(1 << 18); cdebug << genesis.boundary(); GenericFarm f; @@ -417,17 +416,16 @@ private: cout << "Benchmarking on platform: " << platformInfo << endl; cout << "Preparing DAG..." << endl; - Ethash::prep(genesis); + genesis.prep(); - genesis.difficulty = u256(1) << 63; - genesis.noteDirty(); + genesis.setDifficulty(u256(1) << 63); f.setWork(genesis); if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); - map results; + map results; uint64_t mean = 0; uint64_t innerMean = 0; for (unsigned i = 0; i <= _trials; ++i) @@ -488,9 +486,9 @@ private: Farm rpc(client); GenericFarm f; if (_m == MinerType::CPU) - f.startCPU(); + f.start("cpu"); else if (_m == MinerType::GPU) - f.startGPU(); + f.start("opencl"); EthashProofOfWork::WorkPackage current; EthashAux::FullType dag; diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h index 67a5397f4..c310b3dd9 100644 --- a/libethcore/BlockInfo.h +++ b/libethcore/BlockInfo.h @@ -128,6 +128,7 @@ public: void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); } void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); } void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); } + void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); } Address const& coinbaseAddress() const { return m_coinbaseAddress; } h256 const& stateRoot() const { return m_stateRoot; } diff --git a/libethereum/Client.h b/libethereum/Client.h index 73609bd71..4523d324b 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -77,7 +77,7 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r); * @brief Main API hub for interfacing with Ethereum. * Not to be used directly - subclass. */ -class Client: public ClientBase, Worker +class Client: public ClientBase, protected Worker { public: /// New-style Constructor. @@ -342,6 +342,8 @@ public: init(_host, _dbPath, _forceAction, _networkId); } + virtual ~SpecialisedClient() { stopWorking(); } + /// Get the object representing the current canonical blockchain. CanonBlockChain const& blockChain() const { return m_bc; } @@ -365,6 +367,8 @@ public: u256 _networkId = 0 ): SpecialisedClient(_host, _gpForAdoption, _dbPath, _forceAction, _networkId) {} + virtual ~EthashClient() { stopWorking(); } + /// 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::tuple getEthashWork() override; diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 30f323369..c29788b9f 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -63,11 +64,17 @@ void connectClients(Client& c1, Client& c2) void mine(State& s, BlockChain const& _bc) { s.commitToMine(_bc); - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + Ethash::BlockHeader header(s.info); + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { - return completed = s.completeMine(sol); + header.m_mixHash = sol.mixHash; + header.m_nonce = sol.nonce; + RLPStream ret; + header.streamRLP(ret); + s.sealBlock(ret); + return true; }); f.setWork(s.info()); f.startCPU(); @@ -77,9 +84,9 @@ void mine(State& s, BlockChain const& _bc) void mine(BlockInfo& _bi) { - GenericFarm f; + GenericFarm f; bool completed = false; - f.onSolutionFound([&](ProofOfWork::Solution sol) + f.onSolutionFound([&](EthashProofOfWork::Solution sol) { _bi.proof = sol; return completed = true; diff --git a/test/libethcore/dagger.cpp b/test/libethcore/dagger.cpp index 8d4cba933..c3cd75b0d 100644 --- a/test/libethcore/dagger.cpp +++ b/test/libethcore/dagger.cpp @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(basic_test) h256 headerHash(o["header_hash"].get_str()); Nonce nonce(o["nonce"].get_str()); BOOST_REQUIRE_EQUAL(headerHash, header.hashWithout()); - BOOST_REQUIRE_EQUAL(nonce, header.nonce); + BOOST_REQUIRE_EQUAL(nonce, header.nonce()); unsigned cacheSize(o["cache_size"].get_int()); h256 cacheHash(o["cache_hash"].get_str()); @@ -73,9 +73,9 @@ BOOST_AUTO_TEST_CASE(basic_test) #endif h256 result(o["result"].get_str()); - EthashProofOfWork::Result r = EthashAux::eval(header); + EthashProofOfWork::Result r = EthashAux::eval(header.seedHash(), header.hashWithout(), header.nonce()); BOOST_REQUIRE_EQUAL(r.value, result); - BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); + BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash()); } } diff --git a/test/libethereum/ClientBase.cpp b/test/libethereum/ClientBase.cpp index a426ff53f..f9d83e9c6 100644 --- a/test/libethereum/ClientBase.cpp +++ b/test/libethereum/ClientBase.cpp @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber); // blockInfo - auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void + auto compareBlockInfos = [](Json::Value const& _b, Ethash::BlockHeader _blockInfo) -> void { LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString())); Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString())); @@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(blocks) ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles()); }; - BlockInfo blockInfo = _client.blockInfo(blockHash); + Ethash::BlockHeader blockInfo(_client.bc().headerData(blockHash)); compareBlockInfos(blockHeader, blockInfo); // blockDetails diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index ce49a4a20..050ab2d25 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -54,7 +55,7 @@ BOOST_AUTO_TEST_CASE(trivialGasPricer) std::shared_ptr gp(new TrivialGasPricer); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); - gp->update(BlockChain(bytes(), TransientDirectory().path(), WithExisting::Kill)); + gp->update(FullBlockChain(bytes(), StateDefinition(), TransientDirectory().path(), WithExisting::Kill)); BOOST_CHECK_EQUAL(gp->ask(State()), 10 * szabo); BOOST_CHECK_EQUAL(gp->bid(), 10 * szabo); } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 28b2e43ab..badabd70c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number()), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -84,11 +84,11 @@ mObject FakeExtVM::exportEnv() { mObject ret; ret["previousHash"] = toString(currentBlock.parentHash()); - ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty, HexPrefix::Add, 1); + ret["currentDifficulty"] = toCompactHex(currentBlock.difficulty(), HexPrefix::Add, 1); ret["currentTimestamp"] = toCompactHex(currentBlock.timestamp(), HexPrefix::Add, 1); ret["currentCoinbase"] = toString(currentBlock.coinbaseAddress()); - ret["currentNumber"] = toCompactHex(currentBlock.number, HexPrefix::Add, 1); - ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit, HexPrefix::Add, 1); + ret["currentNumber"] = toCompactHex(currentBlock.number(), HexPrefix::Add, 1); + ret["currentGasLimit"] = toCompactHex(currentBlock.gasLimit(), HexPrefix::Add, 1); return ret; } @@ -107,7 +107,7 @@ void FakeExtVM::importEnv(mObject& _o) lastHashes = test::lastHashes(currentBlock.number); currentBlock.gasLimit = toInt(_o["currentGasLimit"]); currentBlock.difficulty = toInt(_o["currentDifficulty"]); - currentBlock.timestamp() = toInt(_o["currentTimestamp"]); + currentBlock.timestamp = toInt(_o["currentTimestamp"]); currentBlock.coinbaseAddress() = Address(_o["currentCoinbase"].get_str()); }