Browse Source

Basic test working with same code for Ethash and BasicAuthority.

cl-refactor
Gav Wood 10 years ago
parent
commit
68b2c8ecbf
  1. 4
      CMakeLists.txt
  2. 2
      alethzero/MainWin.cpp
  3. 1
      eth/main.cpp
  4. 17
      ethminer/MinerAux.h
  5. 6
      exp/CMakeLists.txt
  6. 86
      exp/main.cpp
  7. 29
      libdevcore/Guards.h
  8. 3
      libdevcore/RLP.h
  9. 9
      libdevcore/TrieDB.h
  10. 43
      libethcore/BasicAuthority.cpp
  11. 16
      libethcore/BasicAuthority.h
  12. 34
      libethcore/BlockInfo.cpp
  13. 64
      libethcore/BlockInfo.h
  14. 3
      libethcore/Common.cpp
  15. 14
      libethcore/Common.h
  16. 163
      libethcore/Ethash.cpp
  17. 52
      libethcore/Ethash.h
  18. 17
      libethcore/EthashAux.cpp
  19. 47
      libethcore/EthashAux.h
  20. 6
      libethcore/Farm.h
  21. 4
      libethcore/Miner.h
  22. 27
      libethcore/ProofOfWork.cpp
  23. 40
      libethcore/ProofOfWork.h
  24. 31
      libethcore/Sealer.h
  25. 136
      libethereum/BlockChain.cpp
  26. 113
      libethereum/BlockChain.h
  27. 11
      libethereum/BlockChainSync.cpp
  28. 24
      libethereum/BlockQueue.cpp
  29. 8
      libethereum/BlockQueue.h
  30. 75
      libethereum/CanonBlockChain.cpp
  31. 45
      libethereum/CanonBlockChain.h
  32. 200
      libethereum/Client.cpp
  33. 119
      libethereum/Client.h
  34. 2
      libethereum/ClientBase.cpp
  35. 4
      libethereum/ClientBase.h
  36. 8
      libethereum/Interface.h
  37. 87
      libethereum/State.cpp
  38. 66
      libethereum/State.h
  39. 4
      libethereum/Utility.cpp
  40. 3
      libethereum/Utility.h
  41. 6
      libweb3jsonrpc/JsonHelper.cpp
  42. 14
      libweb3jsonrpc/JsonHelper.h
  43. 3
      test/libethcore/dagger.cpp
  44. 3
      test/libethereum/stateOriginal.cpp

4
CMakeLists.txt

@ -432,8 +432,8 @@ endif ()
add_subdirectory(libethcore) add_subdirectory(libethcore)
if (GENERAL) if (GENERAL)
# add_subdirectory(libevm) add_subdirectory(libevm)
# add_subdirectory(libethereum) add_subdirectory(libethereum)
# add_subdirectory(libwebthree) # add_subdirectory(libwebthree)
endif () endif ()

2
alethzero/MainWin.cpp

@ -208,7 +208,7 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount); 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"); QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray(); m_networkConfig = s.value("peers").toByteArray();

1
eth/main.cpp

@ -32,7 +32,6 @@
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libevmcore/Instruction.h> #include <libevmcore/Instruction.h>
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libevm/VM.h> #include <libevm/VM.h>
#include <libevm/VMFactory.h> #include <libevm/VMFactory.h>

17
ethminer/MinerAux.h

@ -37,7 +37,6 @@
#include <libdevcore/StructuredLogger.h> #include <libdevcore/StructuredLogger.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/Farm.h> #include <libethcore/Farm.h>
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
@ -387,7 +386,6 @@ public:
#endif #endif
} }
#if ETH_USING_ETHASH
enum class MinerType enum class MinerType
{ {
CPU, CPU,
@ -412,10 +410,10 @@ private:
genesis.difficulty = 1 << 18; genesis.difficulty = 1 << 18;
cdebug << genesis.boundary(); cdebug << genesis.boundary();
GenericFarm<Ethash> f; GenericFarm<EthashProofOfWork> f;
f.onSolutionFound([&](ProofOfWork::Solution) { return false; }); 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 << "Benchmarking on platform: " << platformInfo << endl;
cout << "Preparing DAG..." << endl; cout << "Preparing DAG..." << endl;
@ -488,20 +486,20 @@ private:
jsonrpc::HttpClient client(_remote); jsonrpc::HttpClient client(_remote);
Farm rpc(client); Farm rpc(client);
GenericFarm<Ethash> f; GenericFarm<EthashProofOfWork> f;
if (_m == MinerType::CPU) if (_m == MinerType::CPU)
f.startCPU(); f.startCPU();
else if (_m == MinerType::GPU) else if (_m == MinerType::GPU)
f.startGPU(); f.startGPU();
ProofOfWork::WorkPackage current; EthashProofOfWork::WorkPackage current;
EthashAux::FullType dag; EthashAux::FullType dag;
while (true) while (true)
try try
{ {
bool completed = false; bool completed = false;
ProofOfWork::Solution solution; EthashProofOfWork::Solution solution;
f.onSolutionFound([&](ProofOfWork::Solution sol) f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{ {
solution = sol; solution = sol;
return completed = true; return completed = true;
@ -595,5 +593,4 @@ private:
string m_farmURL = "http://127.0.0.1:8545"; string m_farmURL = "http://127.0.0.1:8545";
unsigned m_farmRecheckPeriod = 500; unsigned m_farmRecheckPeriod = 500;
bool m_precompute = true; bool m_precompute = true;
#endif
}; };

6
exp/CMakeLists.txt

@ -25,12 +25,12 @@ if (JSONRPC)
endif() endif()
#target_link_libraries(${EXECUTABLE} webthree) #target_link_libraries(${EXECUTABLE} webthree)
#target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} ethereum)
#target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} p2p)
if (ETHASHCL) if (ETHASHCL)
# target_link_libraries(${EXECUTABLE} ethash-cl) # target_link_libraries(${EXECUTABLE} ethash-cl)
# target_link_libraries(${EXECUTABLE} ethash) # target_link_libraries(${EXECUTABLE} ethash)
# target_link_libraries(${EXECUTABLE} ${OpenCL_LIBRARIES}) # target_link_libraries(${EXECUTABLE} OpenCL)
endif() endif()
target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ethcore)
install( TARGETS ${EXECUTABLE} DESTINATION bin) install( TARGETS ${EXECUTABLE} DESTINATION bin)

86
exp/main.cpp

@ -46,7 +46,6 @@
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcrypto/SecretStore.h> #include <libdevcrypto/SecretStore.h>
#include <libp2p/All.h> #include <libp2p/All.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Farm.h> #include <libethcore/Farm.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethereum/All.h> #include <libethereum/All.h>
@ -71,13 +70,16 @@ namespace fs = boost::filesystem;
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h> #include <libethcore/Ethash.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <libethereum/All.h>
#include <libethereum/AccountDiff.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/Client.h>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace eth; using namespace eth;
#endif #endif
#if 1 #if 0
int main() int main()
{ {
BlockInfo bi; BlockInfo bi;
@ -124,9 +126,7 @@ int main()
return 0; return 0;
} }
#elif 0 #elif 0
int main() int main()
{ {
cdebug << pbkdf2("password", asBytes("salt"), 1, 32); cdebug << pbkdf2("password", asBytes("salt"), 1, 32);
@ -135,10 +135,7 @@ int main()
cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16); cdebug << pbkdf2("testpassword", fromHex("de5742f1f1045c402296422cee5a8a9ecf0ac5bf594deca1170d22aef33a79cf"), 262144, 16);
return 0; return 0;
} }
#elif 0 #elif 0
int main() int main()
{ {
cdebug << "EXP"; cdebug << "EXP";
@ -162,9 +159,7 @@ int main()
ret = orderedTrieRoot(data); ret = orderedTrieRoot(data);
cdebug << ret; cdebug << ret;
} }
#elif 0 #elif 0
int main() int main()
{ {
KeyManager keyman; KeyManager keyman;
@ -186,7 +181,6 @@ int main()
cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2); cdebug << "Secret key for " << a2 << "is" << keyman.secret(a2);
} }
#elif 0 #elif 0
int main() int main()
{ {
@ -246,15 +240,15 @@ int main()
#elif 0 #elif 0
int main() int main()
{ {
GenericFarm<Ethash> f; GenericFarm<EthashProofOfWork> f;
BlockInfo genesis = CanonBlockChain::genesis(); BlockInfo genesis = CanonBlockChain::genesis();
genesis.difficulty = 1 << 18; genesis.difficulty = 1 << 18;
cdebug << genesis.boundary(); cdebug << genesis.boundary();
auto mine = [](GenericFarm<Ethash>& f, BlockInfo const& g, unsigned timeout) { auto mine = [](GenericFarm<EthashProofOfWork>& f, BlockInfo const& g, unsigned timeout) {
BlockInfo bi = g; BlockInfo bi = g;
bool completed = false; bool completed = false;
f.onSolutionFound([&](ProofOfWork::Solution sol) f.onSolutionFound([&](EthashProofOfWork::Solution sol)
{ {
bi.proof = sol; bi.proof = sol;
return completed = true; return completed = true;
@ -289,23 +283,16 @@ int main()
return 0; return 0;
} }
#elif 0 #elif 1
void mine(State& s, BlockChain const& _bc, SealEngineFace* _se)
void mine(State& s, BlockChain const& _bc)
{ {
s.commitToMine(_bc); s.commitToMine(_bc);
GenericFarm<ProofOfWork> f; Notified<bytes> sealed;
bool completed = false; _se->onSealGenerated([&](bytes const& sealedHeader){ sealed = sealedHeader; });
f.onSolutionFound([&](ProofOfWork::Solution sol) _se->generateSeal(s.info());
{ sealed.waitNot({});
return completed = s.completeMine<ProofOfWork>(sol); s.sealBlock(sealed);
});
f.setWork(s.info());
f.startCPU();
while (!completed)
this_thread::sleep_for(chrono::milliseconds(20));
} }
#elif 0
int main() int main()
{ {
cnote << "Testing State..."; 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())); Defaults::setDBPath(boost::filesystem::temp_directory_path().string() + "/" + toString(chrono::system_clock::now().time_since_epoch().count()));
OverlayDB stateDB = State::openDB(); using Sealer = Ethash;
CanonBlockChain bc; CanonBlockChain<Sealer> bc;
cout << 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()); OverlayDB stateDB = State::openDB(bc.genesisHash());
cout << s; 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. // Sync up - this won't do much until we use the last state.
s.sync(bc); s.sync(bc);
cout << s; cnote << s;
// Mine to get some ether! // 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); 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. // Inject a transaction to transfer funds from miner to me.
Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret()); Transaction t(1000, 10000, 30000, me.address(), bytes(), s.transactionsFrom(myMiner.address()), myMiner.secret());
assert(t.sender() == myMiner.address()); assert(t.sender() == myMiner.address());
s.execute(bc.lastHashes(), t); s.execute(bc.lastHashes(), t);
cout << s; cnote << s;
// Mine to get some ether and set in stone. // Mine to get some ether and set in stone.
s.commitToMine(bc); s.commitToMine(bc);
s.commitToMine(bc); s.commitToMine(bc);
mine(s, bc); mine(s, bc, se);
bc.attemptImport(s.blockData(), stateDB); bc.attemptImport(s.blockData(), stateDB);
cout << bc; cnote << bc;
s.sync(bc); s.sync(bc);
cout << s; cnote << s;
return 0; return 0;
} }

29
libdevcore/Guards.h

@ -22,6 +22,7 @@
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <condition_variable>
#include <atomic> #include <atomic>
#include <boost/thread.hpp> #include <boost/thread.hpp>
@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex;
using SharedMutex = boost::shared_mutex; using SharedMutex = boost::shared_mutex;
using Guard = std::lock_guard<std::mutex>; using Guard = std::lock_guard<std::mutex>;
using UniqueGuard = std::unique_lock<std::mutex>;
using RecursiveGuard = std::lock_guard<std::recursive_mutex>; using RecursiveGuard = std::lock_guard<std::recursive_mutex>;
using ReadGuard = boost::shared_lock<boost::shared_mutex>; using ReadGuard = boost::shared_lock<boost::shared_mutex>;
using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>; using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
@ -74,6 +76,33 @@ private:
}; };
using SpinGuard = std::lock_guard<SpinLock>; using SpinGuard = std::lock_guard<SpinLock>;
template <class N>
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 <class F> void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); }
template <class R, class P> void wait(std::chrono::duration<R, P> _d) const { N old; { UniqueGuard l(m_mutex); old = m_value; } waitNot(_d, old); }
template <class R, class P> void wait(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value == _v;}); }
template <class R, class P> void waitNot(std::chrono::duration<R, P> _d, N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait_for(l, _d, [&](){return m_value != _v;}); }
template <class R, class P, class F> void wait(std::chrono::duration<R, P> _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. /** @brief Simple block guard.
* The expression/block following is guarded though the given mutex. * The expression/block following is guarded though the given mutex.
* Usage: * Usage:

3
libdevcore/RLP.h

@ -393,6 +393,9 @@ public:
/// Read the byte stream. /// 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; } 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. /// 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); } void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); }

9
libdevcore/TrieDB.h

@ -231,8 +231,11 @@ public:
} }
} }
protected: /// Get the underlying database.
DB* db() const { return m_db; } /// @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: private:
RLPStream& streamNode(RLPStream& _s, bytes const& _b); RLPStream& streamNode(RLPStream& _s, bytes const& _b);
@ -383,6 +386,7 @@ public:
using Super::isEmpty; using Super::isEmpty;
using Super::root; using Super::root;
using Super::db;
using Super::leftOvers; using Super::leftOvers;
using Super::check; using Super::check;
@ -435,6 +439,7 @@ public:
using Super::check; using Super::check;
using Super::open; using Super::open;
using Super::setRoot; using Super::setRoot;
using Super::db;
std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); }
bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); }

43
libethcore/BasicAuthority.cpp

@ -19,6 +19,7 @@
* @date 2014 * @date 2014
*/ */
#include <libdevcore/CommonJS.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "BasicAuthority.h" #include "BasicAuthority.h"
#include "BlockInfo.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: return { { "sig", toJS(m_sig) } };
BasicAuthoritySeal(Signature const& _sig): m_sig(_sig) {} }
virtual bytes sealedHeader(BlockInfo const& _bi) const
{
BasicAuthority::BlockHeader h(_bi);
h.m_sig = m_sig;
RLPStream ret;
h.streamRLP(ret);
return ret.out();
}
private:
Signature m_sig;
};
class BasicAuthoritySealEngine: public SealEngineFace class BasicAuthoritySealEngine: public SealEngineBase<BasicAuthority>
{ {
public: public:
void setSecret(Secret const& _s) { m_secret = _s; } void setSecret(Secret const& _s) { m_secret = _s; }
void generateSeal(BlockInfo const& _bi) void generateSeal(BlockInfo const& _bi)
{ {
BasicAuthoritySeal s(sign(m_secret, _bi.hashWithout())); BasicAuthority::BlockHeader h(_bi);
m_onSealGenerated(&s); h.m_sig = sign(m_secret, _bi.hashWithout());
RLPStream ret;
h.streamRLP(ret);
m_onSealGenerated(ret.out());
} }
void onSealGenerated(std::function<void(SealFace const* s)> const& _f) { m_onSealGenerated = _f; } void onSealGenerated(std::function<void(bytes const&)> const& _f) { m_onSealGenerated = _f; }
bool isMining() const { return false; } bool isWorking() const { return false; }
MiningProgress miningProgress() const { return MiningProgress(); } WorkingProgress workingProgress() const { return WorkingProgress(); }
private: private:
virtual bool onOptionChanging(std::string const& _name, bytes const& _value) virtual bool onOptionChanging(std::string const& _name, bytes const& _value)
@ -107,7 +108,7 @@ private:
} }
Secret m_secret; Secret m_secret;
std::function<void(SealFace const* s)> m_onSealGenerated; std::function<void(bytes const& s)> m_onSealGenerated;
}; };
SealEngineFace* BasicAuthority::createSealEngine() SealEngineFace* BasicAuthority::createSealEngine()

16
libethcore/BasicAuthority.h

@ -52,33 +52,31 @@ class BasicAuthority
friend class ::BasicAuthoritySealEngine; friend class ::BasicAuthoritySealEngine;
public: public:
// TODO: remove
struct Result {};
struct WorkPackage {};
static const WorkPackage NullWorkPackage;
static std::string name() { return "BasicAuthority"; } static std::string name() { return "BasicAuthority"; }
static unsigned revision() { return 0; } static unsigned revision() { return 0; }
static SealEngineFace* createSealEngine(); static SealEngineFace* createSealEngine();
class BlockHeaderRaw: public BlockInfo class BlockHeaderRaw: public BlockInfo
{ {
friend class ::BasicAuthoritySeal; friend class ::BasicAuthoritySealEngine;
public: public:
static const unsigned SealFields = 1;
bool verify() const; bool verify() const;
bool preVerify() const; bool preVerify() const;
WorkPackage package() const { return NullWorkPackage; }
Signature sig() const { return m_sig; } Signature sig() const { return m_sig; }
StringHashMap jsInfo() const;
protected: protected:
BlockHeaderRaw() = default; BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
static const unsigned SealFields = 1;
void populateFromHeader(RLP const& _header, Strictness _s); 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 streamRLPFields(RLPStream& _s) const { _s << m_sig; }
void clear() { m_sig = Signature(); } void clear() { m_sig = Signature(); }
void noteDirty() const {} void noteDirty() const {}

34
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); RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block);
m_hash = sha3(header.data()); m_hash = _hashWith ? _hashWith : sha3(header.data());
populateFromHeader(header, _s); populateFromHeader(header, _s);
} }
@ -58,7 +58,7 @@ void BlockInfo::clear()
gasUsed = 0; gasUsed = 0;
timestamp = 0; timestamp = 0;
extraData.clear(); extraData.clear();
m_hashWithout = h256(); noteDirty();
} }
h256 const& BlockInfo::boundary() const h256 const& BlockInfo::boundary() const
@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
if (number > ~(unsigned)0) if (number > ~(unsigned)0)
BOOST_THROW_EXCEPTION(InvalidNumber()); BOOST_THROW_EXCEPTION(InvalidNumber());
if (_s != CheckNothing) if (_s != CheckNothing && gasUsed > gasLimit)
{ BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
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())));
}
} }
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; }; 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); gasLimit = selectGasLimit(_parent);
gasUsed = 0; gasUsed = 0;
difficulty = calculateDifficulty(_parent); difficulty = calculateDifficulty(_parent);
parentHash = _parent.hash();
} }
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const 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 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. // Check timestamp is after previous timestamp.
if (parentHash) if (parentHash)
{ {

64
libethcore/BlockInfo.h

@ -42,10 +42,18 @@ enum Strictness
{ {
CheckEverything, CheckEverything,
QuickNonce, QuickNonce,
IgnoreNonce, IgnoreSeal,
CheckNothing CheckNothing
}; };
enum BlockDataType
{
HeaderData,
BlockData
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
/** @brief Encapsulation of a block header. /** @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 * 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 * from some given RLP block serialisation with the static fromHeader(), through the method
@ -69,7 +77,10 @@ enum Strictness
*/ */
struct BlockInfo struct BlockInfo
{ {
friend class BlockChain;
public: public:
static const unsigned BasicFields = 13;
// TODO: make them all private! // TODO: make them all private!
h256 parentHash; h256 parentHash;
h256 sha3Uncles; h256 sha3Uncles;
@ -78,7 +89,7 @@ public:
h256 transactionsRoot; h256 transactionsRoot;
h256 receiptsRoot; h256 receiptsRoot;
LogBloom logBloom; LogBloom logBloom;
u256 difficulty; u256 difficulty; // TODO: pull out into BlockHeader
u256 number; u256 number;
u256 gasLimit; u256 gasLimit;
u256 gasUsed; u256 gasUsed;
@ -86,10 +97,12 @@ public:
bytes extraData; bytes extraData;
BlockInfo(); 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(bytes const& _block) { return headerHashFromBlock(&_block); }
static h256 headerHashFromBlock(bytesConstRef _block); static h256 headerHashFromBlock(bytesConstRef _block);
static RLP extractHeader(bytesConstRef _block);
explicit operator bool() const { return timestamp != Invalid256; } explicit operator bool() const { return timestamp != Invalid256; }
@ -121,17 +134,14 @@ public:
/// sha3 of the header only. /// sha3 of the header only.
h256 const& hashWithout() const; h256 const& hashWithout() const;
h256 const& hash() const { return m_hash; } h256 const& hash() const { if (m_hash) return m_hash; throw NoHashRecorded(); }
protected:
static RLP extractHeader(bytesConstRef _block);
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce);
void streamRLPFields(RLPStream& _s) const;
void clear(); void clear();
void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); } 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. mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised.
@ -152,35 +162,50 @@ template <class BlockInfoSub>
class BlockHeaderPolished: public BlockInfoSub class BlockHeaderPolished: public BlockInfoSub
{ {
public: public:
static const unsigned Fields = BlockInfoSub::BasicFields + BlockInfoSub::SealFields;
BlockHeaderPolished() {} BlockHeaderPolished() {}
BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {} BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {}
explicit BlockHeaderPolished(bytes const& _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 _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { populate(_block, _s, _h); } 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); } // deprecated - just use constructor instead.
static BlockHeaderPolished fromHeader(bytesConstRef _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()) { BlockHeaderPolished ret; ret.populateFromHeader(RLP(_header), _s, _h); return ret; } 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) void populateFromParent(BlockHeaderPolished const& _parent)
{ {
noteDirty(); noteDirty();
BlockInfo::parentHash = _parent.hash(); BlockInfo::parentHash = _parent.hash();
BlockInfo::populateFromParent(_parent); BlockInfo::populateFromParent(_parent);
BlockInfoSub::populateFromParent(_parent);
} }
// TODO: consider making private.
void verifyParent(BlockHeaderPolished const& _parent) void verifyParent(BlockHeaderPolished const& _parent)
{ {
if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash()) if (BlockInfo::parentHash && BlockInfo::parentHash != _parent.hash())
BOOST_THROW_EXCEPTION(InvalidParentHash()); BOOST_THROW_EXCEPTION(InvalidParentHash());
BlockInfo::verifyParent(_parent); 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; BlockInfo::m_hash = _h;
if (_h) if (_h)
assert(_h == dev::sha3(_header.data())); assert(_h == dev::sha3(_header.data()));
else
BlockInfo::m_hash = dev::sha3(_header.data());
if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields) if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields)
BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
@ -213,6 +238,13 @@ public:
if (_i == WithProof) if (_i == WithProof)
BlockInfoSub::streamRLPFields(_s); BlockInfoSub::streamRLPFields(_s);
} }
bytes sealFieldsRLP() const
{
RLPStream s;
BlockInfoSub::streamRLPFields(s);
return s.out();
}
}; };
} }

3
libethcore/Common.cpp

@ -29,7 +29,6 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include "Exceptions.h" #include "Exceptions.h"
#include "ProofOfWork.h"
#include "BlockInfo.h" #include "BlockInfo.h"
using namespace std; using namespace std;
using namespace dev; using namespace dev;
@ -57,7 +56,7 @@ Network const c_network = Network::Frontier;
Network const c_network = Network::Olympic; Network const c_network = Network::Olympic;
#endif #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<pair<u256, string>> const& units() vector<pair<u256, string>> const& units()
{ {

14
libethcore/Common.h

@ -124,10 +124,16 @@ struct ImportRequirements
using value = unsigned; using value = unsigned;
enum enum
{ {
ValidNonce = 1, ///< Validate nonce ValidSeal = 1, ///< Validate seal
DontHave = 2, ///< Avoid old blocks DontHave = 2, ///< Avoid old blocks
CheckUncles = 4, ///< Check uncle nonces UncleBasic = 4, ///< Check the basic structure of the uncles.
Default = ValidNonce | DontHave | CheckUncles 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. * @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; } // MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed. uint64_t hashes = 0; ///< Total number of hashes computed.

163
libethcore/Ethash.cpp

@ -33,6 +33,7 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/CryptoPP.h> #include <libdevcrypto/CryptoPP.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethash/ethash.h> #include <libethash/ethash.h>
@ -49,6 +50,7 @@
#include "Exceptions.h" #include "Exceptions.h"
#include "Farm.h" #include "Farm.h"
#include "Miner.h" #include "Miner.h"
#include "Params.h"
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
@ -57,8 +59,6 @@ namespace dev
namespace eth namespace eth
{ {
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
h256 const& Ethash::BlockHeaderRaw::seedHash() const h256 const& Ethash::BlockHeaderRaw::seedHash() const
{ {
if (!m_seedHash) if (!m_seedHash)
@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _
ex << errinfo_nonce(m_nonce); ex << errinfo_nonce(m_nonce);
ex << errinfo_mixHash(m_mixHash); ex << errinfo_mixHash(m_mixHash);
ex << errinfo_seedHash(seedHash()); 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_ethashResult(make_tuple(er.value, er.mixHash));
ex << errinfo_hash256(hashWithout()); ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(difficulty); ex << errinfo_difficulty(difficulty);
@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _
ex << errinfo_nonce(m_nonce); ex << errinfo_nonce(m_nonce);
BOOST_THROW_EXCEPTION(ex); 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 bool Ethash::BlockHeaderRaw::preVerify() const
@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const
return slow; 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<int(unsigned)> const& _f) const void Ethash::BlockHeaderRaw::prep(std::function<int(unsigned)> const& _f) const
{ {
EthashAux::full(seedHash(), true, _f); 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<int(unsigned)> const& _f) const
class EthashCPUMiner: public GenericMiner<Ethash>, Worker class EthashCPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{ {
public: public:
EthashCPUMiner(GenericMiner<Ethash>::ConstructionInfo const& _ci): GenericMiner<Ethash>(_ci), Worker("miner" + toString(index())) {} EthashCPUMiner(GenericMiner<EthashProofOfWork>::ConstructionInfo const& _ci): GenericMiner<EthashProofOfWork>(_ci), Worker("miner" + toString(index())) {}
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo(); static std::string platformInfo();
@ -190,7 +214,7 @@ private:
}; };
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
class EthashGPUMiner: public GenericMiner<Ethash>, Worker class EthashGPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{ {
friend class dev::eth::EthashCLHook; friend class dev::eth::EthashCLHook;
@ -234,66 +258,84 @@ private:
}; };
#endif #endif
class EthashSeal: public SealFace struct EthashSealEngine: public SealEngineBase<Ethash>
{ {
public: friend class Ethash;
EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {}
virtual bytes sealedHeader(BlockInfo const& _bi) const
{
Ethash::BlockHeader h(_bi);
h.m_mixHash = m_mixHash;
h.m_nonce = m_nonce;
RLPStream ret;
h.streamRLP(ret);
return ret.out();
}
private:
h256 m_mixHash;
h64 m_nonce;
};
struct EthashSealEngine: public SealEngineFace
{
public: public:
EthashSealEngine() EthashSealEngine()
{ {
map<string, GenericFarm<Ethash>::SealerDescriptor> sealers; map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<Ethash>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<Ethash>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }}; sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
#if ETH_ETHASHCL #if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<Ethash>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<Ethash>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }}; sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif #endif
m_farm.setSealers(sealers); 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 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 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.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); Ethash::ensurePrecomputed((unsigned)_bi.number);
} }
void onSealGenerated(std::function<void(SealFace const*)> const& _f) override void onSealGenerated(std::function<void(bytes const&)> 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; 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); m_sealing.m_mixHash = sol.mixHash;
_f(&s); m_sealing.m_nonce = sol.nonce;
RLPStream ret;
m_sealing.streamRLP(ret);
_f(ret.out());
return true; return true;
}); });
} }
private: private:
bool m_opencl = false; bool m_opencl = false;
eth::GenericFarm<Ethash> m_farm; eth::GenericFarm<EthashProofOfWork> m_farm;
std::string m_sealer; std::string m_sealer = "cpu";
Ethash::BlockHeader m_sealing;
}; };
void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_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<GenericFarmFace<EthashProofOfWork>&>(e->m_farm).submitProof(EthashProofOfWork::Solution{_nonce, _mixHash}, nullptr);
}
bool Ethash::isWorking(SealEngineFace* _engine)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.isMining();
return false;
}
WorkingProgress Ethash::workingProgress(SealEngineFace* _engine)
{
if (EthashSealEngine* e = dynamic_cast<EthashSealEngine*>(_engine))
return e->m_farm.miningProgress();
return WorkingProgress();
}
SealEngineFace* Ethash::createSealEngine() SealEngineFace* Ethash::createSealEngine()
{ {
return new EthashSealEngine; return new EthashSealEngine;
@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop()
{ {
ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce); ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer); h256 value = h256((uint8_t*)&ethashReturn.result, h256::ConstructFromPointer);
if (value <= boundary && submitProof(Ethash::Solution{(h64)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)})) if (value <= boundary && submitProof(EthashProofOfWork::Solution{(h64)(u64)tryNonce, h256((uint8_t*)&ethashReturn.mix_hash, h256::ConstructFromPointer)}))
break; break;
if (!(hashCount % 100)) if (!(hashCount % 100))
accumulateHashes(100); accumulateHashes(100);
@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo()
#if ETH_ETHASHCL || !ETH_TRUE #if ETH_ETHASHCL || !ETH_TRUE
using UniqueGuard = std::unique_lock<std::mutex>;
template <class N>
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 <class F> 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 class EthashCLHook: public ethash_cl_miner::search_hook
{ {
public: public:

52
libethcore/Ethash.h

@ -53,59 +53,42 @@ public:
static unsigned revision(); static unsigned revision();
static SealEngineFace* createSealEngine(); static SealEngineFace* createSealEngine();
// TODO: remove or virtualize using Nonce = h64;
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(); }
h256 boundary; static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce);
h256 headerHash; ///< When h256() means "pause until notified a new work package is available". static bool isWorking(SealEngineFace* _engine);
h256 seedHash; static WorkingProgress workingProgress(SealEngineFace* _engine);
};
static const WorkPackage NullWorkPackage;
class BlockHeaderRaw: public BlockInfo class BlockHeaderRaw: public BlockInfo
{ {
friend class EthashSeal; friend class EthashSealEngine;
public: public:
static const unsigned SealFields = 2;
bool verify() const; bool verify() const;
bool preVerify() const; bool preVerify() const;
void prep(std::function<int(unsigned)> const& _f = std::function<int(unsigned)>()) const; void prep(std::function<int(unsigned)> const& _f = std::function<int(unsigned)>()) const;
WorkPackage package() const;
h256 const& seedHash() 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; } h256 const& mixHash() const { return m_mixHash; }
StringHashMap jsInfo() const;
protected: protected:
BlockHeaderRaw() = default; BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {} BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
static const unsigned SealFields = 2;
void populateFromHeader(RLP const& _header, Strictness _s); 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 noteDirty() const { m_seedHash = h256(); }
void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; } void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; }
private: private:
h64 m_nonce; Nonce m_nonce;
h256 m_mixHash; h256 m_mixHash;
mutable h256 m_seedHash; mutable h256 m_seedHash;
@ -115,13 +98,6 @@ public:
// TODO: Move elsewhere (EthashAux?) // TODO: Move elsewhere (EthashAux?)
static void ensurePrecomputed(unsigned _number); 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;
}; };
} }

17
libethcore/EthashAux.cpp

@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr; 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() EthashAux::~EthashAux()
{ {
} }
@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0; 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); ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success) if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure()); 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); ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success) if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure()); 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) DEV_GUARDED(get()->x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock()) if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce); return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
{ {
return Ethash::Result{ ~h256(), h256() }; return EthashProofOfWork::Result{ ~h256(), h256() };
} }
} }

47
libethcore/EthashAux.h

@ -34,6 +34,47 @@ namespace eth
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; }; 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 class EthashAux
{ {
public: public:
@ -46,7 +87,7 @@ public:
LightAllocation(h256 const& _seedHash); LightAllocation(h256 const& _seedHash);
~LightAllocation(); ~LightAllocation();
bytesConstRef data() const; 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; ethash_light_t light;
uint64_t size; uint64_t size;
}; };
@ -55,7 +96,7 @@ public:
{ {
FullAllocation(ethash_light_t _light, ethash_callback_t _cb); FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation(); ~FullAllocation();
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const; EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const; bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); } uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t 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. /// 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<int(unsigned)> const& _f = std::function<int(unsigned)>()); static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
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: private:
EthashAux() {} EthashAux() {}

6
libethcore/Farm.h

@ -123,9 +123,9 @@ public:
* @brief Get information on the progress of mining this work package. * @brief Get information on the progress of mining this work package.
* @return The progress with mining so far. * @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::milliseconds>(std::chrono::steady_clock::now() - m_lastStart).count(); p.ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_lastStart).count();
{ {
ReadGuard l2(x_minerWork); ReadGuard l2(x_minerWork);
@ -195,7 +195,7 @@ private:
std::atomic<bool> m_isMining = {false}; std::atomic<bool> m_isMining = {false};
mutable SharedMutex x_progress; mutable SharedMutex x_progress;
mutable MiningProgress m_progress; mutable WorkingProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart; std::chrono::steady_clock::time_point m_lastStart;
SolutionFound m_onSolutionFound; SolutionFound m_onSolutionFound;

4
libethcore/Miner.h

@ -36,9 +36,9 @@ namespace dev
namespace eth 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"; _out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s";
return _out; return _out;

27
libethcore/ProofOfWork.cpp

@ -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 <http://www.gnu.org/licenses/>.
*/
/** @file ProofOfWork.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "ProofOfWork.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace eth;

40
libethcore/ProofOfWork.h

@ -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 <http://www.gnu.org/licenses/>.
*/
/** @file ProofOfWork.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include <libdevcore/RLP.h>
#include <libdevcrypto/Common.h>
#include "Common.h"
//#include "Ethash.h"
#include "BasicAuthority.h"
namespace dev
{
namespace eth
{
using ProofOfWork = BasicAuthority;
}
}

31
libethcore/Sealer.h

@ -25,6 +25,7 @@
#include <functional> #include <functional>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcore/RLP.h>
#include "Common.h" #include "Common.h"
namespace dev namespace dev
@ -34,28 +35,22 @@ namespace eth
class BlockInfo; class BlockInfo;
class SealFace
{
public:
virtual bool wouldSealHeader(BlockInfo const&) const { return true; }
virtual bytes sealedHeader(BlockInfo const& _bi) const = 0;
};
class SealEngineFace class SealEngineFace
{ {
public: 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(); } 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; } 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 strings sealers() const { return { "default" }; }
virtual void setSealer(std::string const&) {} virtual void setSealer(std::string const&) {}
virtual void generateSeal(BlockInfo const& _bi) = 0; virtual void generateSeal(BlockInfo const& _bi) = 0;
virtual void onSealGenerated(std::function<void(SealFace const* s)> const& _f) = 0; virtual void onSealGenerated(std::function<void(bytes const& s)> const& _f) = 0;
virtual void disable() {} virtual void cancelGeneration() {}
// TODO: rename & generalise
virtual bool isMining() const { return false; }
virtual MiningProgress miningProgress() const { return MiningProgress(); }
protected: protected:
virtual bool onOptionChanging(std::string const&, bytes const&) { return true; } virtual bool onOptionChanging(std::string const&, bytes const&) { return true; }
@ -66,5 +61,15 @@ private:
std::unordered_map<std::string, bytes> m_options; std::unordered_map<std::string, bytes> m_options;
}; };
template <class Sealer>
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(); }
};
} }
} }

136
libethereum/BlockChain.cpp

@ -35,12 +35,12 @@
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
#include "GenesisInfo.h" #include "GenesisInfo.h"
#include "State.h" #include "State.h"
#include "Utility.h"
#include "Defaults.h" #include "Defaults.h"
using namespace std; using namespace std;
@ -48,7 +48,7 @@ using namespace dev;
using namespace dev::eth; using namespace dev::eth;
namespace js = json_spirit; namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 0
#define ETH_TIMED_IMPORTS 1 #define ETH_TIMED_IMPORTS 1
#ifdef _WIN32 #ifdef _WIN32
@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif #endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p) BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p):
m_genesisState(_genesisState)
{ {
// initialise deathrow. // initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize); 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. // Initialise with the genesis as the last block on the longest chain.
m_genesisBlock = _genesisBlock; m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data()); 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) if (open(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p); rebuild(_path, _p);
@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB); ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// Open a fresh state DB // Open a fresh state DB
State s(State::openDB(path, WithExisting::Kill), BaseState::CanonGenesis); State s = genesisState(State::openDB(path, m_genesisHash, WithExisting::Kill));
// Clear all memos ready for replay. // Clear all memos ready for replay.
m_details.clear(); m_details.clear();
@ -286,9 +291,9 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
{ {
bytes b = block(queryExtras<BlockHash, ExtraBlockHash>(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value); bytes b = block(queryExtras<BlockHash, ExtraBlockHash>(h256(u256(d)), m_blockHashes, x_blockHashes, NullBlockHash, oldExtrasDB).value);
BlockInfo bi(b); BlockInfo bi(&b);
if (_prepPoW) if (_prepPoW)
Ethash::prep(bi); Ethash::ensurePrecomputed((unsigned)bi.number);
if (bi.parentHash != lastHash) if (bi.parentHash != lastHash)
{ {
@ -351,7 +356,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
// Nonce & uncle nonces already verified in verification thread at this point. // Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r; ImportRoute r;
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500) DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks; fresh += r.liveBlocks;
dead += r.deadBlocks; dead += r.deadBlocks;
goodTransactions += r.goodTranactions; goodTransactions += r.goodTranactions;
@ -388,7 +393,7 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
{ {
try 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&) catch (UnknownParent&)
{ {
@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try try
#endif #endif
{ {
block = verifyBlock(_block, m_onBad, _ir); block = verifyBlock(&_block, m_onBad, _ir);
} }
#if ETH_CATCH #if ETH_CATCH
catch (Exception& ex) catch (Exception& ex)
@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
auto parentBlock = block(_block.info.parentHash); auto parentBlock = block(_block.info.parentHash);
clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; 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) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1); 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. // 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. // Get total difficulty increase and update state, checking it.
State s(_db); 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) for (unsigned i = 0; i < s.pending().size(); ++i)
{ {
@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db)
try try
{ {
cout << "block..." << flush; cout << "block..." << flush;
BlockInfo bi = info(h); BlockInfo bi(block(h));
cout << "details..." << flush; cout << "extras..." << flush;
BlockDetails bd = details(h); details(h);
cout << "state..." << flush; cout << "state..." << flush;
if (_db.exists(bi.stateRoot)) if (_db.exists(bi.stateRoot))
break; break;
@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const
return m_blocks[_hash]; return m_blocks[_hash];
} }
VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) bytes BlockChain::headerData(h256 const& _hash) const
{ {
VerifiedBlockRef res; if (_hash == m_genesisHash)
try return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes();
{
Strictness strictness = Strictness::CheckEverything;
if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce;
res.info.populate(_block, strictness);
res.info.verifyInternals(&_block);
}
catch (Exception& ex)
{ {
ex << errinfo_phase(1); ReadGuard l(x_blocks);
ex << errinfo_now(time(0)); auto it = m_blocks.find(_hash);
ex << errinfo_block(_block); if (it != m_blocks.end())
if (_onBad) return BlockInfo::extractHeader(&it->second).data().toBytes();
_onBad(ex);
throw;
} }
RLP r(_block); string d;
unsigned i = 0; m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
for (auto const& uncle: r[2])
{ if (d.empty())
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])
{ {
bytesConstRef d = tr.data(); cwarn << "Couldn't find requested block:" << _hash;
try return bytes();
{
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;
} }
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;
}

113
libethereum/BlockChain.h

@ -37,6 +37,7 @@
#include "Transaction.h" #include "Transaction.h"
#include "BlockQueue.h" #include "BlockQueue.h"
#include "VerifiedBlock.h" #include "VerifiedBlock.h"
#include "State.h"
namespace std namespace std
{ {
@ -86,6 +87,13 @@ enum {
}; };
using ProgressCallback = std::function<void(unsigned, unsigned)>; using ProgressCallback = std::function<void(unsigned, unsigned)>;
using StateDefinition = std::unordered_map<Address, Account>;
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath, h256 const& _genesisHash);
};
/** /**
* @brief Implements the blockchain database. All data this gives is disk-backed. * @brief Implements the blockchain database. All data this gives is disk-backed.
@ -94,7 +102,7 @@ using ProgressCallback = std::function<void(unsigned, unsigned)>;
class BlockChain class BlockChain
{ {
public: 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(); ~BlockChain();
/// Attempt a database re-open. /// 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). /// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const; bool isKnown(h256 const& _hash) const;
/// Get the familial details concerning a block (or the most recent mined if none given). Thread-safe. /// 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(block(_hash), IgnoreNonce, _hash); } BlockInfo info(h256 const& _hash) const { return BlockInfo(headerData(_hash), CheckNothing, _hash, HeaderData); }
BlockInfo info() const { return info(currentHash()); } 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. /// 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(h256 const& _hash) const;
bytes block() const { return block(currentHash()); } 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. /// 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<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); } BlockDetails details(h256 const& _hash) const { return queryExtras<BlockDetails, ExtraDetails>(_hash, m_details, x_details, NullBlockDetails); }
@ -264,13 +275,16 @@ public:
/// Deallocate unused data. /// Deallocate unused data.
void garbageCollect(bool _force = false); void garbageCollect(bool _force = false);
/// Verify block and prepare it for enactment
static VerifiedBlockRef verifyBlock(bytes const& _block, std::function<void(Exception&)> const& _onBad = std::function<void(Exception&)>(), ImportRequirements::value _ir = ImportRequirements::Default);
/// Change the function that is called with a bad block. /// Change the function that is called with a bad block.
template <class T> void setOnBad(T const& _t) { m_onBad = _t; } template <class T> 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<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const = 0;
protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust); unsigned open(std::string const& _path, WithExisting _we = WithExisting::Trust);
@ -345,6 +359,7 @@ private:
/// Genesis block info. /// Genesis block info.
h256 m_genesisHash; h256 m_genesisHash;
bytes m_genesisBlock; bytes m_genesisBlock;
std::unordered_map<Address, Account> m_genesisState;
ldb::ReadOptions m_readOptions; ldb::ReadOptions m_readOptions;
ldb::WriteOptions m_writeOptions; ldb::WriteOptions m_writeOptions;
@ -354,6 +369,88 @@ private:
friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
}; };
template <class Sealer>
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<void(Exception&)> 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<BlockInfo&>(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); std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc);
} }

11
libethereum/BlockChainSync.cpp

@ -183,11 +183,11 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
for (unsigned i = 0; i < itemCount; ++i) 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)) if (_peer->m_sub.noteBlock(h))
{ {
_peer->addRating(10); _peer->addRating(10);
switch (host().bq().import(_r[i].data(), host().chain())) switch (host().bq().import(_r[i].data()))
{ {
case ImportResult::Success: case ImportResult::Success:
success++; success++;
@ -219,8 +219,7 @@ void BlockChainSync::onPeerBlocks(std::shared_ptr<EthereumPeer> _peer, RLP const
logNewBlock(h); logNewBlock(h);
if (m_state == SyncState::NewBlocks) if (m_state == SyncState::NewBlocks)
{ {
BlockInfo bi; BlockInfo bi(_r[i].data());
bi.populateFromHeader(_r[i][0]);
if (bi.number > maxUnknownNumber) if (bi.number > maxUnknownNumber)
{ {
maxUnknownNumber = bi.number; maxUnknownNumber = bi.number;
@ -268,13 +267,13 @@ void BlockChainSync::onPeerNewBlock(std::shared_ptr<EthereumPeer> _peer, RLP con
{ {
DEV_INVARIANT_CHECK; DEV_INVARIANT_CHECK;
RecursiveGuard l(x_sync); RecursiveGuard l(x_sync);
auto h = BlockInfo::headerHash(_r[0].data()); auto h = BlockInfo::headerHashFromBlock(_r[0].data());
if (_r.itemCount() != 2) if (_r.itemCount() != 2)
_peer->disable("NewBlock without 2 data fields."); _peer->disable("NewBlock without 2 data fields.");
else else
{ {
switch (host().bq().import(_r[0].data(), host().chain())) switch (host().bq().import(_r[0].data()))
{ {
case ImportResult::Success: case ImportResult::Success:
_peer->addRating(100); _peer->addRating(100);

24
libethereum/BlockQueue.cpp

@ -110,7 +110,7 @@ void BlockQueue::verifierBody()
swap(work.block, res.blockData); swap(work.block, res.blockData);
try try
{ {
res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, CheckEverything);
} }
catch (...) 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(); clog(BlockQueueTraceChannel) << std::this_thread::get_id();
// Check if we already know this block. // Check if we already know this block.
h256 h = BlockInfo::headerHash(_block); h256 h = BlockInfo::headerHashFromBlock(_block);
clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import...";
@ -200,14 +200,12 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
return ImportResult::AlreadyKnown; return ImportResult::AlreadyKnown;
} }
// VERIFY: populates from the block and checks the block is internally coherent.
BlockInfo bi; BlockInfo bi;
try try
{ {
// TODO: quick verify // TODO: quick verification of seal - will require BlockQueue to be templated on Sealer
bi.populate(_block); // VERIFY: populates from the block and checks the block is internally coherent.
bi.verifyInternals(_block); bi = m_bc->verifyBlock(_block, m_onBad, ImportRequirements::None).info;
} }
catch (Exception const& _e) 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; clog(BlockQueueTraceChannel) << "Block" << h << "is" << bi.number << "parent is" << bi.parentHash;
// Check block doesn't already exist first! // Check block doesn't already exist first!
if (_bc.isKnown(h)) if (m_bc->isKnown(h))
{ {
cblockq << "Already known in chain."; cblockq << "Already known in chain.";
return ImportResult::AlreadyInChain; return ImportResult::AlreadyInChain;
@ -240,7 +238,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
m_unknownSize += _block.size(); m_unknownSize += _block.size();
m_unknownCount++; m_unknownCount++;
m_difficulty += bi.difficulty; 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; return unknown ? ImportResult::FutureTimeUnknown : ImportResult::FutureTimeKnown;
} }
else else
@ -253,7 +251,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo
// bad parent; this is bad too, note it as such // bad parent; this is bad too, note it as such
return ImportResult::BadChain; 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. // 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; clog(BlockQueueTraceChannel) << "OK - queued as unknown parent:" << bi.parentHash;
@ -374,7 +372,7 @@ bool BlockQueue::doneDrain(h256s const& _bad)
return !m_readySet.empty(); return !m_readySet.empty();
} }
void BlockQueue::tick(BlockChain const& _bc) void BlockQueue::tick()
{ {
vector<pair<h256, bytes>> todo; vector<pair<h256, bytes>> todo;
{ {
@ -406,7 +404,7 @@ void BlockQueue::tick(BlockChain const& _bc)
cblockq << "Importing" << todo.size() << "past-future blocks."; cblockq << "Importing" << todo.size() << "past-future blocks.";
for (auto const& b: todo) for (auto const& b: todo)
import(&b.second, _bc); import(&b.second);
} }
template <class T> T advanced(T _t, unsigned _n) template <class T> T advanced(T _t, unsigned _n)

8
libethereum/BlockQueue.h

@ -76,11 +76,13 @@ public:
BlockQueue(); BlockQueue();
~BlockQueue(); ~BlockQueue();
void setChain(BlockChain const& _bc) { m_bc = &_bc; }
/// Import a block into the queue. /// 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. /// 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. /// 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. /// Don't forget to call doneDrain() once you're done importing.
@ -138,6 +140,8 @@ private:
void updateBad_WITH_LOCK(h256 const& _bad); void updateBad_WITH_LOCK(h256 const& _bad);
void drainVerified_WITH_BOTH_LOCKS(); 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. 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_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain import. h256Hash m_readySet; ///< All blocks ready for chain import.

75
libethereum/CanonBlockChain.cpp

@ -27,7 +27,6 @@
#include <libdevcore/RLP.h> #include <libdevcore/RLP.h>
#include <libdevcore/FileSystem.h> #include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Params.h> #include <libethcore/Params.h>
#include <liblll/Compiler.h> #include <liblll/Compiler.h>
@ -41,14 +40,44 @@ namespace js = json_spirit;
#define ETH_CATCH 1 #define ETH_CATCH 1
std::unordered_map<Address, Account> const& dev::eth::genesisState() std::unique_ptr<Ethash::BlockHeader> CanonBlockChain<Ethash>::s_genesis;
boost::shared_mutex CanonBlockChain<Ethash>::x_genesis;
Nonce CanonBlockChain<Ethash>::s_nonce(u64(42));
std::string CanonBlockChain<Ethash>::s_genesisStateJSON;
CanonBlockChain<Ethash>::CanonBlockChain(std::string const& _path, WithExisting _we, ProgressCallback const& _pc):
FullBlockChain<Ethash>(createGenesisBlock(), createGenesisState(), _path, _we, _pc)
{
}
bytes CanonBlockChain<Ethash>::createGenesisBlock()
{
RLPStream block(3);
h256 stateRoot;
{
MemoryDB db;
SecureTrieDB<Address, MemoryDB> 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<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
{ {
static std::unordered_map<Address, Account> s_ret; static std::unordered_map<Address, Account> s_ret;
if (s_ret.empty()) if (s_ret.empty())
{ {
js::mValue val; 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()) for (auto account: val.get_obj())
{ {
u256 balance; u256 balance;
@ -68,53 +97,29 @@ std::unordered_map<Address, Account> const& dev::eth::genesisState()
return s_ret; return s_ret;
} }
// TODO: place Registry in here. void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json)
std::unique_ptr<BlockInfo> 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<Address, MemoryDB> 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)
{ {
WriteGuard l(x_genesis);
s_genesisStateJSON = _json;
s_genesis.reset();
} }
void CanonBlockChain::setGenesisNonce(Nonce const& _n) void CanonBlockChain<Ethash>::setGenesisNonce(Nonce const& _n)
{ {
WriteGuard l(x_genesis); WriteGuard l(x_genesis);
s_nonce = _n; s_nonce = _n;
s_genesis.reset(); s_genesis.reset();
} }
BlockInfo const& CanonBlockChain::genesis() Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis()
{ {
UpgradableGuard l(x_genesis); UpgradableGuard l(x_genesis);
if (!s_genesis) if (!s_genesis)
{ {
auto gb = createGenesisBlock(); auto gb = createGenesisBlock();
UpgradeGuard ul(l); UpgradeGuard ul(l);
s_genesis.reset(new BlockInfo); s_genesis.reset(new Ethash::BlockHeader);
s_genesis->populate(&gb); s_genesis->populate(&gb, CheckEverything);
} }
return *s_genesis; return *s_genesis;
} }

45
libethereum/CanonBlockChain.h

@ -26,6 +26,7 @@
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include "BlockDetails.h" #include "BlockDetails.h"
#include "Account.h" #include "Account.h"
@ -45,7 +46,32 @@ std::unordered_map<Address, Account> const& genesisState();
* @threadsafe * @threadsafe
* @todo Make not memory hog (should actually act as a cache and deallocate old entries). * @todo Make not memory hog (should actually act as a cache and deallocate old entries).
*/ */
class CanonBlockChain: public BlockChain template <class Sealer>
class CanonBlockChain: public FullBlockChain<Sealer>
{
public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain<Sealer>(std::string(), _we, _pc) {}
CanonBlockChain(std::string const& _path, WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()):
FullBlockChain<Sealer>(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<Ethash>: public FullBlockChain<Ethash>
{ {
public: public:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {} CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {}
@ -53,22 +79,35 @@ public:
~CanonBlockChain() {} ~CanonBlockChain() {}
/// @returns the genesis block header. /// @returns the genesis block header.
static BlockInfo const& genesis(); static Ethash::BlockHeader const& genesis();
/// @returns the genesis block as its RLP-encoded byte array. /// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead. /// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static bytes createGenesisBlock(); 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<Address, Account> createGenesisState();
/// Alter the value of the genesis block's nonce. /// 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 /// @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. /// program, before anything has had the chance to use this class at all.
static void setGenesisNonce(Nonce const& _n); 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: private:
/// Static genesis info and its lock. /// Static genesis info and its lock.
static boost::shared_mutex x_genesis; static boost::shared_mutex x_genesis;
static std::unique_ptr<BlockInfo> s_genesis; static std::unique_ptr<Ethash::BlockHeader> s_genesis;
static Nonce s_nonce; static Nonce s_nonce;
static std::string s_genesisStateJSON;
}; };
} }

200
libethereum/Client.cpp

@ -72,47 +72,43 @@ static const Addresses c_canaries =
Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph Address("ace7813896a84d3f5f80223916a5353ab16e46e6") // christoph
}; };
VersionChecker::VersionChecker(string const& _dbPath) Client::Client(std::shared_ptr<GasPricer> _gp):
Worker("eth", 0),
m_gp(_gp ? _gp : make_shared<TrivialGasPricer>())
{ {
upgradeDatabase(_dbPath);
} }
Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId)
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _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<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): m_bq.setChain(bc());
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_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30); 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_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_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); }); bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_sealEngine = shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); });
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; m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common _extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size()) if (_dbPath.size())
Defaults::setDBPath(_dbPath); Defaults::setDBPath(_dbPath);
doWork(); doWork();
startWorking(); 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) if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000)
this_thread::sleep_for(std::chrono::milliseconds(500)); this_thread::sleep_for(std::chrono::milliseconds(500));
return m_bq.import(&_block, bc(), _isSafe); return m_bq.import(&_block, _isSafe);
} }
tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max) tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max)
{ {
stopWorking(); stopWorking();
return m_bc.sync(m_bq, m_stateDB, _max); return bc().sync(m_bq, m_stateDB, _max);
} }
void Client::onBadBlock(Exception& _ex) const void Client::onBadBlock(Exception& _ex) const
@ -294,7 +290,7 @@ void Client::startedWorking()
clog(ClientTrace) << "startedWorking()"; clog(ClientTrace) << "startedWorking()";
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine) DEV_READ_GUARDED(x_preMine)
{ {
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
@ -309,7 +305,7 @@ void Client::doneWorking()
// Synchronise the state according to the head of the block chain. // Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones. // TODO: currently it contains keys for *all* blocks. Make it remove old ones.
DEV_WRITE_GUARDED(x_preMine) DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc); m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine) DEV_READ_GUARDED(x_preMine)
{ {
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
@ -328,7 +324,7 @@ void Client::killChain()
m_tq.clear(); m_tq.clear();
m_bq.clear(); m_bq.clear();
m_farm.disable(); m_sealEngine->cancelGeneration();
{ {
WriteGuard l(x_postMine); WriteGuard l(x_postMine);
@ -340,10 +336,10 @@ void Client::killChain()
m_working = State(); m_working = State();
m_stateDB = OverlayDB(); m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
m_bc.reopen(Defaults::dbPath(), 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); 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) void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
{ {
// TODO: more precise check on whether the txs match. // TODO: more precise check on whether the txs match.
auto d = m_bc.info(_block); auto d = bc().info(_block);
auto receipts = m_bc.receipts(_block).receipts; auto receipts = bc().receipts(_block).receipts;
Guard l(x_filtersWatches); Guard l(x_filtersWatches);
io_changed.insert(ChainChangedFilter); io_changed.insert(ChainChangedFilter);
@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable)
startMining(); startMining();
} }
MiningProgress Client::miningProgress() const bool Client::isMining() const
{ {
if (m_farm.isMining()) return Ethash::isWorking(m_sealEngine.get());
return m_farm.miningProgress(); }
return MiningProgress();
WorkingProgress Client::miningProgress() const
{
if (Ethash::isWorking(m_sealEngine.get()))
return Ethash::workingProgress(m_sealEngine.get());
return WorkingProgress();
} }
uint64_t Client::hashrate() const uint64_t Client::hashrate() const
{ {
if (m_farm.isMining()) if (Ethash::isWorking(m_sealEngine.get()))
return m_farm.miningProgress().rate(); return Ethash::workingProgress(m_sealEngine.get()).rate();
return 0; return 0;
} }
@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret; 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<ProofOfWork>(_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_syncMin = 1;
unsigned static const c_syncMax = 1000; unsigned static const c_syncMax = 1000;
double static const c_targetDuration = 1; double static const c_targetDuration = 1;
@ -553,7 +515,7 @@ void Client::syncBlockQueue()
ImportRoute ir; ImportRoute ir;
unsigned count; unsigned count;
Timer t; 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(); double elapsed = t.elapsed();
if (count) if (count)
@ -577,7 +539,7 @@ void Client::syncTransactionQueue()
TransactionReceipts newPendingReceipts; TransactionReceipts newPendingReceipts;
DEV_WRITE_GUARDED(x_working) 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()) if (newPendingReceipts.empty())
return; return;
@ -590,7 +552,7 @@ void Client::syncTransactionQueue()
for (size_t i = 0; i < newPendingReceipts.size(); i++) for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); 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(); onPostStateChanged();
// Tell watches about the new transactions. // Tell watches about the new transactions.
@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& h: _ir.deadBlocks) for (auto const& h: _ir.deadBlocks)
{ {
clog(ClientTrace) << "Dead block:" << h; 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); clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t, IfDropped::Retry); m_tq.import(t, IfDropped::Retry);
@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
newPreMine = m_preMine; newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks. // 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()) if (preChanged || m_postMine.address() != m_preMine.address())
{ {
@ -700,7 +662,7 @@ void Client::rejigMining()
{ {
clog(ClientTrace) << "Rejigging mining..."; clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working) DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc, m_extraData); m_working.commitToMine(bc(), m_extraData);
DEV_READ_GUARDED(x_working) DEV_READ_GUARDED(x_working)
{ {
DEV_WRITE_GUARDED(x_postMine) DEV_WRITE_GUARDED(x_postMine)
@ -709,10 +671,10 @@ void Client::rejigMining()
} }
if (m_wouldMine) if (m_wouldMine)
m_farm.sealBlock(m_miningInfo); m_sealEngine->generateSeal(m_miningInfo);
} }
if (!m_wouldMine) if (!m_wouldMine)
m_farm.disable(); m_sealEngine->cancelGeneration();
} }
void Client::noteChanged(h256Hash const& _filters) void Client::noteChanged(h256Hash const& _filters)
@ -768,7 +730,7 @@ void Client::tick()
{ {
m_report.ticks++; m_report.ticks++;
checkWatchGarbage(); checkWatchGarbage();
m_bq.tick(m_bc); m_bq.tick();
m_lastTick = chrono::system_clock::now(); m_lastTick = chrono::system_clock::now();
if (m_report.ticks == 15) if (m_report.ticks == 15)
clog(ClientTrace) << activityReport(); clog(ClientTrace) << activityReport();
@ -792,7 +754,7 @@ void Client::checkWatchGarbage()
uninstallWatch(i); uninstallWatch(i);
// blockchain GC // blockchain GC
m_bc.garbageCollect(); bc().garbageCollect();
m_lastGarbageCollection = chrono::system_clock::now(); m_lastGarbageCollection = chrono::system_clock::now();
} }
@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const
try try
{ {
State ret(m_stateDB); State ret(m_stateDB);
ret.populateFromChain(m_bc, _block); ret.populateFromChain(bc(), _block);
return ret.fromPending(_txi); return ret.fromPending(_txi);
} }
catch (Exception& ex) catch (Exception& ex)
@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const
try try
{ {
State ret(m_stateDB); State ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(m_bc, _block); PopulationStatistics s = ret.populateFromChain(bc(), _block);
if (o_stats) if (o_stats)
swap(s, *o_stats); swap(s, *o_stats);
return ret; return ret;
@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const
auto h = m_host.lock(); auto h = m_host.lock();
return h ? h->status() : SyncStatus(); 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<h256, h256, h256> 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<h256, h256, h256>();
// 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<h256, h256, h256>(bh.boundary(), bh.hashWithout(), bh.seedHash());
}
bool EthashClient::submitEthashWork(h256 const& _mixHash, h64 const& _nonce)
{
Ethash::manuallySubmitWork(m_sealEngine.get(), _mixHash, _nonce);
return true;
}

119
libethereum/Client.h

@ -60,12 +60,6 @@ enum ClientWorkState
Deleted Deleted
}; };
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath);
};
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; }; 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 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; }; 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. * @brief Main API hub for interfacing with Ethereum.
* Not to be used directly - subclass.
*/ */
class Client: public ClientBase, Worker class Client: public ClientBase, Worker
{ {
public: public:
/// New-style Constructor. /// New-style Constructor.
explicit Client( /// Any final derived class's constructor should make sure they call init().
p2p::Host* _host, explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
explicit Client(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
/// Destructor. /// Destructor.
virtual ~Client(); virtual ~Client();
@ -129,7 +112,7 @@ public:
/// Get the object representing the current state of Ethereum. /// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; } dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain. /// 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. /// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block queue. /// Get some information on the block queue.
@ -176,26 +159,16 @@ public:
/// NOT thread-safe /// NOT thread-safe
void stopMining() override { m_wouldMine = false; rejigMining(); } void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now? /// Are we mining now?
bool isMining() const override { return m_farm.isMining(); } bool isMining() const override;
/// Are we mining now? /// Are we mining now?
bool wouldMine() const override { return m_wouldMine; } bool wouldMine() const override { return m_wouldMine; }
/// The hashrate... /// The hashrate...
uint64_t hashrate() const override; uint64_t hashrate() const override;
/// Check the progress of the mining. /// Check the progress of the mining.
MiningProgress miningProgress() const override; WorkingProgress miningProgress() const override;
/// Get and clear the mining history. /// Get and clear the mining history.
std::list<MineInfo> miningHistory(); std::list<MineInfo> 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: // Debug stuff:
DownloadMan const* downloadMan() const; DownloadMan const* downloadMan() const;
@ -218,12 +191,20 @@ public:
/// Set the extra data that goes into mined blocks. /// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; } void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head. /// 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: 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 /// InterfaceStub methods
virtual BlockChain& bc() override { return m_bc; } virtual BlockChain& bc() override = 0;
virtual BlockChain const& bc() const override { return m_bc; } virtual BlockChain const& bc() const override = 0;
/// Returns the state object for the full block (i.e. the terminal state) for index _h. /// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock. /// 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. /// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Hash const& _filters); void noteChanged(h256Hash const& _filters);
private: /// Submit
bool submitSealed(bytes const& _s);
protected:
/// Called when Worker is starting. /// Called when Worker is starting.
void startedWorking() override; void startedWorking() override;
@ -291,8 +275,6 @@ private:
/// @warning May be called from any thread. /// @warning May be called from any thread.
void onBadBlock(Exception& _ex) const; 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). BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer. std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
@ -339,5 +321,64 @@ private:
bytes m_extraData; bytes m_extraData;
}; };
template <class Sealer>
class SpecialisedClient: public Client
{
public:
explicit SpecialisedClient(
p2p::Host* _host,
std::shared_ptr<GasPricer> _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<SealEngineFace>(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<Sealer> 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<Sealer> m_bc; ///< Maintains block database.
};
class EthashClient: public SpecialisedClient<Ethash>
{
public:
/// Trivial forwarding constructor.
explicit EthashClient(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
): SpecialisedClient<Ethash>(_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<h256, h256, h256> 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; }
};
} }
} }

2
libethereum/ClientBase.cpp

@ -357,7 +357,7 @@ BlockInfo ClientBase::uncle(h256 _blockHash, unsigned _i) const
auto bl = bc().block(_blockHash); auto bl = bc().block(_blockHash);
RLP b(bl); RLP b(bl);
if (_i < b[2].itemCount()) if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data()); return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData);
else else
return BlockInfo(); return BlockInfo();
} }

4
libethereum/ClientBase.h

@ -156,9 +156,7 @@ public:
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); } virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); } virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); } virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } virtual WorkingProgress 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")); }
State asOf(BlockNumber _h) const; State asOf(BlockNumber _h) const;

8
libethereum/Interface.h

@ -25,7 +25,7 @@
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libdevcore/Guards.h> #include <libdevcore/Guards.h>
#include <libdevcrypto/Common.h> #include <libdevcrypto/Common.h>
#include <libethcore/ProofOfWork.h> #include <libethcore/Ethash.h>
#include "LogFilter.h" #include "LogFilter.h"
#include "Transaction.h" #include "Transaction.h"
#include "AccountDiff.h" #include "AccountDiff.h"
@ -207,12 +207,12 @@ public:
virtual uint64_t hashrate() const = 0; virtual uint64_t hashrate() const = 0;
/// Get hash of the current block to be mined minus the nonce (the 'work hash'). /// Get hash of the current block to be mined minus the nonce (the 'work hash').
virtual ProofOfWork::WorkPackage getWork() = 0; virtual std::tuple<h256, h256, h256> getEthashWork() { BOOST_THROW_EXCEPTION(InterfaceNotSupported("Interface::getEthashWork")); }
/// Submit the nonce for the proof-of-work. /// 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. /// Check the progress of the mining.
virtual MiningProgress miningProgress() const = 0; virtual WorkingProgress miningProgress() const = 0;
protected: protected:
int m_default = PendingBlock; int m_default = PendingBlock;

87
libethereum/State.cpp

@ -55,7 +55,7 @@ const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; }
const char* StateTrace::name() { return EthViolet "" EthGray ""; } const char* StateTrace::name() { return EthViolet "" EthGray ""; }
const char* StateChat::name() { return EthViolet "" EthWhite ""; } 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; 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"); 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); boost::filesystem::create_directories(path);
ldb::Options o; ldb::Options o;
@ -103,20 +103,9 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
paranoia("beginning of Genesis construction.", true); paranoia("beginning of Genesis construction.", true);
if (_bs == BaseState::CanonGenesis) m_previousBlock.clear();
{ m_currentBlock.clear();
dev::eth::commit(genesisState(), m_db, m_state); // assert(m_state.root() == m_previousBlock.stateRoot);
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);
paranoia("end of normal construction.", true); paranoia("end of normal construction.", true);
} }
@ -139,17 +128,16 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const&
// Non-genesis: // Non-genesis:
// 1. Start at parent's end state (state root). // 1. Start at parent's end state (state root).
BlockInfo bip; BlockInfo bip(_bc.block(bi.parentHash));
bip.populate(_bc.block(bi.parentHash)); sync(_bc, bi.parentHash, bip);
sync(_bc, bi.parentHash, bip, _ir);
// 2. Enact the block's transactions onto this state. // 2. Enact the block's transactions onto this state.
m_ourAddress = bi.coinbaseAddress; m_ourAddress = bi.coinbaseAddress;
Timer t; Timer t;
auto vb = BlockChain::verifyBlock(b); auto vb = _bc.verifyBlock(&b, function<void(Exception&)>(), _ir);
ret.verify = t.elapsed(); ret.verify = t.elapsed();
t.restart(); t.restart();
enact(vb, _bc, _ir); enact(vb, _bc);
ret.enact = t.elapsed(); ret.enact = t.elapsed();
} }
else else
@ -157,7 +145,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const&
// Genesis required: // Genesis required:
// We know there are no transactions, so just populate directly. // We know there are no transactions, so just populate directly.
m_state.init(); m_state.init();
sync(_bc, _h, bi, _ir); sync(_bc, _h, bi);
} }
return ret; return ret;
@ -294,7 +282,7 @@ void State::ensureCached(std::unordered_map<Address, Account>& _cache, Address _
void State::commit() 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(); m_cache.clear();
} }
@ -303,9 +291,8 @@ bool State::sync(BlockChain const& _bc)
return sync(_bc, _bc.currentHash()); 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; bool ret = false;
// BLOCK // BLOCK
BlockInfo bi = _bi ? _bi : _bc.info(_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 << "Unable to sync to" << bi.hash() << "; state root" << bi.stateRoot << "not found in database.";
cwarn << "Database corrupt: contains block without stateRoot:" << bi; cwarn << "Database corrupt: contains block without stateRoot:" << bi;
cwarn << "Bailing."; cwarn << "Try rescuing the database by running: eth --rescue";
exit(-1); exit(-1);
} }
m_previousBlock = bi; m_previousBlock = bi;
@ -404,7 +391,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor
return ret; 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 #if ETH_TIMED_ENACTMENTS
Timer t; Timer t;
@ -432,7 +419,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
t.restart(); t.restart();
#endif #endif
sync(_bc, _block.info.parentHash, BlockInfo(), _ir); sync(_bc, _block.info.parentHash, BlockInfo());
resetCurrent(); resetCurrent();
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
@ -441,7 +428,7 @@ u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, Impor
#endif #endif
m_previousBlock = biParent; m_previousBlock = biParent;
auto ret = enact(_block, _bc, _ir); auto ret = enact(_block, _bc);
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
enactment = t.elapsed(); enactment = t.elapsed();
@ -591,7 +578,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
RLP rlp(_block); RLP rlp(_block);
cleanup(false); cleanup(false);
BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); BlockInfo bi(_block, (_ir & ImportRequirements::ValidSeal) ? CheckEverything : IgnoreSeal);
m_currentBlock = bi; m_currentBlock = bi;
m_currentBlock.verifyInternals(_block); m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty(); m_currentBlock.noteDirty();
@ -611,7 +598,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire
return ret.empty() ? "[]" : (ret + "]"); 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); DEV_TIMED_FUNCTION_ABOVE(500);
@ -627,8 +614,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
BOOST_THROW_EXCEPTION(InvalidParentHash()); BOOST_THROW_EXCEPTION(InvalidParentHash());
// Populate m_currentBlock with the correct values. // Populate m_currentBlock with the correct values.
m_currentBlock = _block.info;
m_currentBlock.noteDirty(); m_currentBlock.noteDirty();
m_currentBlock = _block.info;
// cnote << "playback begins:" << m_state.root(); // cnote << "playback begins:" << m_state.root();
// cnote << m_state; // cnote << m_state;
@ -672,7 +659,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
InvalidReceiptsStateRoot ex; InvalidReceiptsStateRoot ex;
ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot);
ex << errinfo_receipts(receipts); 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); BOOST_THROW_EXCEPTION(ex);
} }
@ -719,7 +706,8 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR
} }
excluded.insert(h); 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; BlockInfo uncleParent;
if (!_bc.isKnown(uncle.parentHash)) if (!_bc.isKnown(uncle.parentHash))
@ -829,6 +817,8 @@ void State::uncommitToMine()
bool State::amIJustParanoid(BlockChain const& _bc) bool State::amIJustParanoid(BlockChain const& _bc)
{ {
(void)_bc;
/*
commitToMine(_bc); commitToMine(_bc);
// Update difficulty according to timestamp. // Update difficulty according to timestamp.
@ -848,7 +838,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
cnote << "PARANOIA root:" << s.rootHash(); cnote << "PARANOIA root:" << s.rootHash();
// s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.populate(&block.out(), false);
// s.m_currentBlock.verifyInternals(&block.out()); // 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<void(Exception&)>(), ImportRequirements::CheckUncles | ImportRequirements::CheckTransactions), _bc); // don't check nonce for this since we haven't mined it yet.
s.cleanup(false); s.cleanup(false);
return true; return true;
} }
@ -860,7 +850,7 @@ bool State::amIJustParanoid(BlockChain const& _bc)
{ {
cwarn << "Bad block: " << _e.what(); cwarn << "Bad block: " << _e.what();
} }
*/
return false; return false;
} }
@ -901,10 +891,9 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
for (auto const& u: us) for (auto const& u: us)
if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about. if (!excluded.count(u)) // ignore any uncles/mainline blocks that we know about.
{ {
BlockInfo ubi(_bc.block(u)); uncleBlockHeaders.push_back(_bc.info(u));
ubi.streamRLP(unclesData, WithProof); unclesData.appendRaw(_bc.headerData(u));
++unclesCount; ++unclesCount;
uncleBlockHeaders.push_back(ubi);
if (unclesCount == 2) if (unclesCount == 2)
break; break;
} }
@ -962,26 +951,30 @@ void State::commitToMine(BlockChain const& _bc, bytes const& _extraData)
m_committedToMine = true; m_committedToMine = true;
} }
void State::completeMine() bool State::sealBlock(bytesConstRef _header)
{ {
cdebug << "Completing mine!"; if (!m_committedToMine)
return false;
cdebug << "Sealing block!";
// Got it! // Got it!
// Compile block: // Compile block:
RLPStream ret; RLPStream ret;
ret.appendList(3); ret.appendList(3);
m_currentBlock.streamRLP(ret, WithProof); ret.appendRaw(_header);
ret.appendRaw(m_currentTxs); ret.appendRaw(m_currentTxs);
ret.appendRaw(m_currentUncles); ret.appendRaw(m_currentUncles);
ret.swapOut(m_currentBytes); ret.swapOut(m_currentBytes);
m_currentBlock.noteDirty(); m_currentBlock = BlockInfo(_header, CheckNothing, h256(), HeaderData);
cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")"; cnote << "Mined " << m_currentBlock.hash() << "(parent: " << m_currentBlock.parentHash << ")";
/* StructuredLogger::minedNewBlock( // TODO: move into Sealer
StructuredLogger::minedNewBlock(
m_currentBlock.hash().abridged(), m_currentBlock.hash().abridged(),
m_currentBlock.proof.nonce.abridged(), "", // Can't give the nonce here.
"", //TODO: chain head hash here ?? "", //TODO: chain head hash here ??
m_currentBlock.parentHash.abridged() m_currentBlock.parentHash.abridged()
);*/ );
// Quickly reset the transactions. // Quickly reset the transactions.
// TODO: Leave this in a better state than this limbo, or at least record that it's in limbo. // 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_receipts.clear();
m_transactionSet.clear(); m_transactionSet.clear();
m_lastTx = m_db; m_lastTx = m_db;
return true;
} }
bool State::addressInUse(Address _id) const bool State::addressInUse(Address _id) const

66
libethereum/State.h

@ -29,7 +29,6 @@
#include <libdevcrypto/OverlayDB.h> #include <libdevcrypto/OverlayDB.h>
#include <libethcore/Exceptions.h> #include <libethcore/Exceptions.h>
#include <libethcore/BlockInfo.h> #include <libethcore/BlockInfo.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/Miner.h> #include <libethcore/Miner.h>
#include <libevm/ExtVMFace.h> #include <libevm/ExtVMFace.h>
#include "Account.h" #include "Account.h"
@ -77,8 +76,7 @@ struct StateSafeExceptions: public LogChannel { static const char* name(); stati
enum class BaseState enum class BaseState
{ {
PreExisting, PreExisting,
Empty, Empty
CanonGenesis
}; };
enum class Permanence enum class Permanence
@ -104,6 +102,7 @@ class State
friend class dev::test::ImportTest; friend class dev::test::ImportTest;
friend class dev::test::StateLoader; friend class dev::test::StateLoader;
friend class Executive; friend class Executive;
friend class BlockChain;
public: public:
/// Default constructor; creates with a blank database prepopulated with the genesis block. /// Default constructor; creates with a blank database prepopulated with the genesis block.
@ -125,7 +124,7 @@ public:
~State(); ~State();
/// Construct state object from arbitrary point in blockchain. /// 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. /// Set the coinbase address for any transactions we do.
/// This causes a complete reset of current block. /// This causes a complete reset of current block.
@ -133,8 +132,8 @@ public:
Address address() const { return m_ourAddress; } Address address() const { return m_ourAddress; }
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary. /// 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(std::string const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust);
static OverlayDB openDB(WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _we); } static OverlayDB openDB(h256 const& _genesisHash, WithExisting _we = WithExisting::Trust) { return openDB(std::string(), _genesisHash, _we); }
OverlayDB const& db() const { return m_db; } OverlayDB const& db() const { return m_db; }
OverlayDB& db() { return m_db; } OverlayDB& db() { return m_db; }
@ -163,22 +162,20 @@ public:
/// Pass in a solution to the proof-of-work. /// Pass in a solution to the proof-of-work.
/// @returns true iff we were previously committed to mining. /// @returns true iff we were previously committed to mining.
template <class PoW> /// TODO: verify it prior to calling this.
bool completeMine(typename PoW::Solution const& _result) /** Commit to DB and build the final block if the previous call to mine()'s result is completion.
{ * Typically looks like:
if (!m_committedToMine) * @code
return false; * while (notYetMined)
* {
m_currentBlock.proof = _result; * // lock
if (!PoW::verify(m_currentBlock)) * commitToMine(_blockChain); // will call uncommitToMine if a repeat.
return false; * completeMine();
* // unlock
// cnote << "Completed" << m_currentBlock.headerHash(WithoutProof) << m_currentBlock.proof.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); * @endcode
*/
completeMine(); bool sealBlock(bytes const& _header) { return sealBlock(&_header); }
bool sealBlock(bytesConstRef _header);
return true;
}
/// Get the complete current block, including valid nonce. /// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true. /// Only valid after mine() returns true.
@ -295,11 +292,11 @@ public:
bool sync(BlockChain const& _bc); bool sync(BlockChain const& _bc);
/// Sync with the block chain, but rather than synching to the latest block, instead sync to the given block. /// 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. /// Execute all transactions within a given block.
/// @returns the additional total difficulty. /// @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. /// 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 /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates
@ -313,19 +310,6 @@ public:
void resetCurrent(); void resetCurrent();
private: 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. /// Undo the changes to the state for committing to mine.
void uncommitToMine(); void uncommitToMine();
@ -340,7 +324,7 @@ private:
/// Execute the given block, assuming it corresponds to m_currentBlock. /// Execute the given block, assuming it corresponds to m_currentBlock.
/// Throws on failure. /// 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. /// Finalise the block, applying the earned rewards.
void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders); void applyRewards(std::vector<BlockInfo> const& _uncleBlockHeaders);
@ -386,7 +370,7 @@ private:
std::ostream& operator<<(std::ostream& _out, State const& _s); std::ostream& operator<<(std::ostream& _out, State const& _s);
template <class DB> template <class DB>
AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db, SecureTrieDB<Address, DB>& _state) AddressHash commit(std::unordered_map<Address, Account> const& _cache, SecureTrieDB<Address, DB>& _state)
{ {
AddressHash ret; AddressHash ret;
for (auto const& i: _cache) for (auto const& i: _cache)
@ -406,7 +390,7 @@ AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db,
} }
else else
{ {
SecureTrieDB<h256, DB> storageDB(&_db, i.second.baseRoot()); SecureTrieDB<h256, DB> storageDB(_state.db(), i.second.baseRoot());
for (auto const& j: i.second.storageOverlay()) for (auto const& j: i.second.storageOverlay())
if (j.second) if (j.second)
storageDB.insert(j.first, rlp(j.second)); storageDB.insert(j.first, rlp(j.second));
@ -419,7 +403,7 @@ AddressHash commit(std::unordered_map<Address, Account> const& _cache, DB& _db,
if (i.second.isFreshCode()) if (i.second.isFreshCode())
{ {
h256 ch = sha3(i.second.code()); h256 ch = sha3(i.second.code());
_db.insert(ch, &i.second.code()); _state.db()->insert(ch, &i.second.code());
s << ch; s << ch;
} }
else else

4
libethereum/Utility.cpp

@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args)
return m_data; 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; 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 minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2]; 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 chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion); string extrasPath = chainPath + "/" + toString(databaseVersion);

3
libethereum/Utility.h

@ -23,6 +23,7 @@
#include <string> #include <string>
#include <libdevcore/Common.h> #include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
namespace dev namespace dev
{ {
@ -42,7 +43,7 @@ namespace eth
*/ */
bytes parseData(std::string const& _args); bytes parseData(std::string const& _args);
void upgradeDatabase(std::string const& _basePath); void upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash);
} }
} }

6
libweb3jsonrpc/JsonHelper.cpp

@ -102,11 +102,9 @@ Json::Value toJson(dev::eth::BlockInfo const& _bi)
res["logsBloom"] = toJS(_bi.logBloom); res["logsBloom"] = toJS(_bi.logBloom);
res["target"] = toJS(_bi.boundary()); res["target"] = toJS(_bi.boundary());
#if ETH_USING_ETHASH
// TODO: move into ProofOfWork. // TODO: move into ProofOfWork.
res["nonce"] = toJS(_bi.proof.nonce); // res["nonce"] = toJS(_bi.proof.nonce);
res["seedHash"] = toJS(_bi.proofCache()); // res["seedHash"] = toJS(_bi.proofCache());
#endif
} }
return res; return res;
} }

14
libweb3jsonrpc/JsonHelper.h

@ -23,6 +23,7 @@
#include <json/json.h> #include <json/json.h>
#include <libethcore/Common.h> #include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethereum/LogFilter.h> #include <libethereum/LogFilter.h>
#include <libwhisper/Message.h> #include <libwhisper/Message.h>
@ -65,6 +66,19 @@ TransactionSkeleton toTransactionSkeleton(Json::Value const& _json);
LogFilter toLogFilter(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. LogFilter toLogFilter(Json::Value const& _json, Interface const& _client); // commented to avoid warning. Uncomment once in use @ PoC-7.
template <class BlockInfoSub>
Json::Value toJson(BlockHeaderPolished<BlockInfoSub> const& _bh)
{
Json::Value res;
if (_bh)
{
res = toJson(static_cast<BlockInfo const&>(_bh));
for (auto const& i: _bh.jsInfo())
res[i.first] = i.second;
}
return res;
}
} }
namespace shh namespace shh

3
test/libethcore/dagger.cpp

@ -24,7 +24,6 @@
#include <random> #include <random>
#include "../JsonSpiritHeaders.h" #include "../JsonSpiritHeaders.h"
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/EthashAux.h> #include <libethcore/EthashAux.h>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include "../TestHelper.h" #include "../TestHelper.h"
@ -74,7 +73,7 @@ BOOST_AUTO_TEST_CASE(basic_test)
#endif #endif
h256 result(o["result"].get_str()); 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.value, result);
BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash);
} }

3
test/libethereum/stateOriginal.cpp

@ -63,7 +63,8 @@ BOOST_AUTO_TEST_CASE(Complex)
CanonBlockChain bc; CanonBlockChain bc;
cout << bc; cout << bc;
State s(stateDB, BaseState::CanonGenesis, myMiner.address()); State s = bc.genesisState(stateDB);
s.setAddress(myMiner.address());
cout << s; cout << s;
// Sync up - this won't do much until we use the last state. // Sync up - this won't do much until we use the last state.

Loading…
Cancel
Save