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.