Browse Source

Basic test working with same code for Ethash and BasicAuthority.

cl-refactor
Gav Wood 10 years ago
parent
commit
e18e3de824
  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)
if (GENERAL)
# add_subdirectory(libevm)
# add_subdirectory(libethereum)
add_subdirectory(libevm)
add_subdirectory(libethereum)
# add_subdirectory(libwebthree)
endif ()

2
alethzero/MainWin.cpp

@ -208,7 +208,7 @@ Main::Main(QWidget *parent) :
statusBar()->addPermanentWidget(ui->chainStatus);
statusBar()->addPermanentWidget(ui->blockCount);
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ProofOfWork::name())).arg(ProofOfWork::revision()).arg(dev::Version));
ui->blockCount->setText(QString("PV%1.%2 D%3 %4-%5 v%6").arg(eth::c_protocolVersion).arg(eth::c_minorProtocolVersion).arg(c_databaseVersion).arg(QString::fromStdString(ethereum()->sealEngine()->name())).arg(ethereum()->sealEngine()->revision()).arg(dev::Version));
QSettings s("ethereum", "alethzero");
m_networkConfig = s.value("peers").toByteArray();

1
eth/main.cpp

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

17
ethminer/MinerAux.h

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

6
exp/CMakeLists.txt

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

86
exp/main.cpp

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

29
libdevcore/Guards.h

@ -22,6 +22,7 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <boost/thread.hpp>
@ -33,6 +34,7 @@ using RecursiveMutex = std::recursive_mutex;
using SharedMutex = boost::shared_mutex;
using Guard = std::lock_guard<std::mutex>;
using UniqueGuard = std::unique_lock<std::mutex>;
using RecursiveGuard = std::lock_guard<std::recursive_mutex>;
using ReadGuard = boost::shared_lock<boost::shared_mutex>;
using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
@ -74,6 +76,33 @@ private:
};
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.
* The expression/block following is guarded though the given mutex.
* Usage:

3
libdevcore/RLP.h

@ -393,6 +393,9 @@ public:
/// Read the byte stream.
bytes const& out() const { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return m_out; }
/// Invalidate the object and steal the output byte stream.
bytes&& invalidate() { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); return std::move(m_out); }
/// Swap the contents of the output stream out for some other byte array.
void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); }

9
libdevcore/TrieDB.h

@ -231,8 +231,11 @@ public:
}
}
protected:
DB* db() const { return m_db; }
/// Get the underlying database.
/// @warning This can be used to bypass the trie code. Don't use these unless you *really*
/// know what you're doing.
DB const* db() const { return m_db; }
DB* db() { return m_db; }
private:
RLPStream& streamNode(RLPStream& _s, bytes const& _b);
@ -383,6 +386,7 @@ public:
using Super::isEmpty;
using Super::root;
using Super::db;
using Super::leftOvers;
using Super::check;
@ -435,6 +439,7 @@ public:
using Super::check;
using Super::open;
using Super::setRoot;
using Super::db;
std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); }
bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); }

43
libethcore/BasicAuthority.cpp

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

16
libethcore/BasicAuthority.h

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

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);
m_hash = sha3(header.data());
RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block);
m_hash = _hashWith ? _hashWith : sha3(header.data());
populateFromHeader(header, _s);
}
@ -58,7 +58,7 @@ void BlockInfo::clear()
gasUsed = 0;
timestamp = 0;
extraData.clear();
m_hashWithout = h256();
noteDirty();
}
h256 const& BlockInfo::boundary() const
@ -133,20 +133,8 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
if (number > ~(unsigned)0)
BOOST_THROW_EXCEPTION(InvalidNumber());
if (_s != CheckNothing)
{
if (gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
}
if (_s != CheckNothing && gasUsed > gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(gasLimit), bigint(gasUsed)) );
}
struct BlockInfoDiagnosticsChannel: public LogChannel { static const char* name() { return EthBlue "" EthWhite ""; } static const int verbosity = 9; };
@ -198,6 +186,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent)
gasLimit = selectGasLimit(_parent);
gasUsed = 0;
difficulty = calculateDifficulty(_parent);
parentHash = _parent.hash();
}
u256 BlockInfo::selectGasLimit(BlockInfo const& _parent) const
@ -222,15 +211,6 @@ u256 BlockInfo::calculateDifficulty(BlockInfo const& _parent) const
void BlockInfo::verifyParent(BlockInfo const& _parent) const
{
// Check difficulty is correct given the two timestamps.
if (difficulty != calculateDifficulty(_parent))
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit ||
gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
// Check timestamp is after previous timestamp.
if (parentHash)
{

64
libethcore/BlockInfo.h

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

3
libethcore/Common.cpp

@ -29,7 +29,6 @@
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
#include "ProofOfWork.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
@ -57,7 +56,7 @@ Network const c_network = Network::Frontier;
Network const c_network = Network::Olympic;
#endif
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (ProofOfWork::revision() << 9);
const unsigned c_databaseVersion = c_databaseBaseVersion + (c_databaseVersionModifier << 8) + (23 << 9);
vector<pair<u256, string>> const& units()
{

14
libethcore/Common.h

@ -124,10 +124,16 @@ struct ImportRequirements
using value = unsigned;
enum
{
ValidNonce = 1, ///< Validate nonce
ValidSeal = 1, ///< Validate seal
DontHave = 2, ///< Avoid old blocks
CheckUncles = 4, ///< Check uncle nonces
Default = ValidNonce | DontHave | CheckUncles
UncleBasic = 4, ///< Check the basic structure of the uncles.
TransactionBasic = 8, ///< Check the basic structure of the transactions.
UncleSeals = 16, ///< Check the basic structure of the uncles.
TransactionSignatures = 32, ///< Check the basic structure of the transactions.
CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals
CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures
Default = ValidSeal | DontHave | CheckUncles | CheckTransactions,
None = 0
};
};
@ -201,7 +207,7 @@ inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&
/**
* @brief Describes the progress of a mining operation.
*/
struct MiningProgress
struct WorkingProgress
{
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.

163
libethcore/Ethash.cpp

@ -33,6 +33,7 @@
#include <libdevcore/Log.h>
#include <libdevcore/Common.h>
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonJS.h>
#include <libdevcrypto/CryptoPP.h>
#include <libdevcore/FileSystem.h>
#include <libethash/ethash.h>
@ -49,6 +50,7 @@
#include "Exceptions.h"
#include "Farm.h"
#include "Miner.h"
#include "Params.h"
using namespace std;
using namespace std::chrono;
@ -57,8 +59,6 @@ namespace dev
namespace eth
{
const Ethash::WorkPackage Ethash::NullWorkPackage = Ethash::WorkPackage();
h256 const& Ethash::BlockHeaderRaw::seedHash() const
{
if (!m_seedHash)
@ -78,7 +78,7 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _
ex << errinfo_nonce(m_nonce);
ex << errinfo_mixHash(m_mixHash);
ex << errinfo_seedHash(seedHash());
Ethash::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
EthashProofOfWork::Result er = EthashAux::eval(seedHash(), hashWithout(), m_nonce);
ex << errinfo_ethashResult(make_tuple(er.value, er.mixHash));
ex << errinfo_hash256(hashWithout());
ex << errinfo_difficulty(difficulty);
@ -93,6 +93,35 @@ void Ethash::BlockHeaderRaw::populateFromHeader(RLP const& _header, Strictness _
ex << errinfo_nonce(m_nonce);
BOOST_THROW_EXCEPTION(ex);
}
if (_s != CheckNothing)
{
if (difficulty < c_minimumDifficulty)
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError(bigint(c_minimumDifficulty), bigint(difficulty)) );
if (gasLimit < c_minGasLimit)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << RequirementError(bigint(c_minGasLimit), bigint(gasLimit)) );
if (number && extraData.size() > c_maximumExtraDataSize)
BOOST_THROW_EXCEPTION(ExtraDataTooBig() << RequirementError(bigint(c_maximumExtraDataSize), bigint(extraData.size())));
}
}
void Ethash::BlockHeaderRaw::verifyParent(BlockHeaderRaw const& _parent)
{
// Check difficulty is correct given the two timestamps.
if (difficulty != calculateDifficulty(_parent))
BOOST_THROW_EXCEPTION(InvalidDifficulty() << RequirementError((bigint)calculateDifficulty(_parent), (bigint)difficulty));
if (gasLimit < c_minGasLimit ||
gasLimit <= _parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor ||
gasLimit >= _parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor)
BOOST_THROW_EXCEPTION(InvalidGasLimit() << errinfo_min((bigint)_parent.gasLimit - _parent.gasLimit / c_gasLimitBoundDivisor) << errinfo_got((bigint)gasLimit) << errinfo_max((bigint)_parent.gasLimit + _parent.gasLimit / c_gasLimitBoundDivisor));
}
void Ethash::BlockHeaderRaw::populateFromParent(BlockHeaderRaw const& _parent)
{
(void)_parent;
}
bool Ethash::BlockHeaderRaw::preVerify() const
@ -143,20 +172,15 @@ bool Ethash::BlockHeaderRaw::verify() const
return slow;
}
Ethash::WorkPackage Ethash::BlockHeaderRaw::package() const
{
WorkPackage ret;
ret.boundary = boundary();
ret.headerHash = hashWithout();
ret.seedHash = seedHash();
return ret;
}
void Ethash::BlockHeaderRaw::prep(std::function<int(unsigned)> const& _f) const
{
EthashAux::full(seedHash(), true, _f);
}
StringHashMap Ethash::BlockHeaderRaw::jsInfo() const
{
return { { "nonce", toJS(m_nonce) }, { "seedHash", toJS(seedHash()) }, { "mixHash", toJS(m_mixHash) } };
}
@ -164,10 +188,10 @@ void Ethash::BlockHeaderRaw::prep(std::function<int(unsigned)> const& _f) const
class EthashCPUMiner: public GenericMiner<Ethash>, Worker
class EthashCPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{
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 std::string platformInfo();
@ -190,7 +214,7 @@ private:
};
#if ETH_ETHASHCL || !ETH_TRUE
class EthashGPUMiner: public GenericMiner<Ethash>, Worker
class EthashGPUMiner: public GenericMiner<EthashProofOfWork>, Worker
{
friend class dev::eth::EthashCLHook;
@ -234,66 +258,84 @@ private:
};
#endif
class EthashSeal: public SealFace
struct EthashSealEngine: public SealEngineBase<Ethash>
{
public:
EthashSeal(h256 const& _mixHash, h64 const& _nonce): m_mixHash(_mixHash), m_nonce(_nonce) {}
virtual bytes sealedHeader(BlockInfo const& _bi) const
{
Ethash::BlockHeader h(_bi);
h.m_mixHash = m_mixHash;
h.m_nonce = m_nonce;
RLPStream ret;
h.streamRLP(ret);
return ret.out();
}
private:
h256 m_mixHash;
h64 m_nonce;
};
friend class Ethash;
struct EthashSealEngine: public SealEngineFace
{
public:
EthashSealEngine()
{
map<string, GenericFarm<Ethash>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<Ethash>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<Ethash>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
#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
m_farm.setSealers(sealers);
}
strings sealers() const override { return { "cpu", "opencl" }; }
strings sealers() const override
{
return {
"cpu"
#if ETH_ETHASHCL
, "opencl"
#endif
};
}
void setSealer(std::string const& _sealer) override { m_sealer = _sealer; }
void disable() override { m_farm.stop(); }
void cancelGeneration() override { m_farm.stop(); }
void generateSeal(BlockInfo const& _bi) override
{
m_farm.setWork(Ethash::BlockHeader(_bi).package());
m_sealing = Ethash::BlockHeader(_bi);
m_farm.setWork(m_sealing);
m_farm.start(m_sealer);
m_farm.setWork(Ethash::BlockHeader(_bi).package()); // TODO: take out one before or one after...
m_farm.setWork(m_sealing); // TODO: take out one before or one after...
Ethash::ensurePrecomputed((unsigned)_bi.number);
}
void onSealGenerated(std::function<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;
EthashSeal s(sol.mixHash, sol.nonce);
_f(&s);
m_sealing.m_mixHash = sol.mixHash;
m_sealing.m_nonce = sol.nonce;
RLPStream ret;
m_sealing.streamRLP(ret);
_f(ret.out());
return true;
});
}
private:
bool m_opencl = false;
eth::GenericFarm<Ethash> m_farm;
std::string m_sealer;
eth::GenericFarm<EthashProofOfWork> m_farm;
std::string m_sealer = "cpu";
Ethash::BlockHeader m_sealing;
};
void Ethash::manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce)
{
if (EthashSealEngine* e = dynamic_cast<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()
{
return new EthashSealEngine;
@ -342,7 +384,7 @@ void EthashCPUMiner::workLoop()
{
ethashReturn = ethash_full_compute(dag->full, *(ethash_h256_t*)w.headerHash.data(), tryNonce);
h256 value = h256((uint8_t*)&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;
if (!(hashCount % 100))
accumulateHashes(100);
@ -403,29 +445,6 @@ std::string EthashCPUMiner::platformInfo()
#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
{
public:

52
libethcore/Ethash.h

@ -53,59 +53,42 @@ public:
static unsigned revision();
static SealEngineFace* createSealEngine();
// TODO: remove or virtualize
struct Solution
{
h64 nonce;
h256 mixHash;
};
// TODO: make private
struct Result
{
h256 value;
h256 mixHash;
};
// TODO: virtualise
struct WorkPackage
{
WorkPackage() = default;
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
using Nonce = h64;
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
static void manuallySubmitWork(SealEngineFace* _engine, h256 const& _mixHash, Nonce _nonce);
static bool isWorking(SealEngineFace* _engine);
static WorkingProgress workingProgress(SealEngineFace* _engine);
class BlockHeaderRaw: public BlockInfo
{
friend class EthashSeal;
friend class EthashSealEngine;
public:
static const unsigned SealFields = 2;
bool verify() const;
bool preVerify() const;
void prep(std::function<int(unsigned)> const& _f = std::function<int(unsigned)>()) const;
WorkPackage package() const;
h256 const& seedHash() const;
h64 const& nonce() const { return m_nonce; }
Nonce const& nonce() const { return m_nonce; }
h256 const& mixHash() const { return m_mixHash; }
StringHashMap jsInfo() const;
protected:
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
static const unsigned SealFields = 2;
void populateFromHeader(RLP const& _header, Strictness _s);
void clear() { m_mixHash = h256(); m_nonce = h64(); }
void populateFromParent(BlockHeaderRaw const& _parent);
void verifyParent(BlockHeaderRaw const& _parent);
void clear() { m_mixHash = h256(); m_nonce = Nonce(); }
void noteDirty() const { m_seedHash = h256(); }
void streamRLPFields(RLPStream& _s) const { _s << m_mixHash << m_nonce; }
private:
h64 m_nonce;
Nonce m_nonce;
h256 m_mixHash;
mutable h256 m_seedHash;
@ -115,13 +98,6 @@ public:
// TODO: Move elsewhere (EthashAux?)
static void ensurePrecomputed(unsigned _number);
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
};
}

17
libethcore/EthashAux.cpp

@ -45,6 +45,11 @@ const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr;
const unsigned EthashProofOfWork::defaultLocalWorkSize = 64;
const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE
const unsigned EthashProofOfWork::defaultMSPerBatch = 0;
const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage();
EthashAux::~EthashAux()
{
}
@ -232,29 +237,29 @@ unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
}
Ethash::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
Ethash::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return Ethash::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
{
DEV_GUARDED(get()->x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
{
return Ethash::Result{ ~h256(), h256() };
return EthashProofOfWork::Result{ ~h256(), h256() };
}
}

47
libethcore/EthashAux.h

@ -34,6 +34,47 @@ namespace eth
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; };
/// Proof of work definition for Ethash.
struct EthashProofOfWork
{
struct Solution
{
Nonce nonce;
h256 mixHash;
};
struct Result
{
h256 value;
h256 mixHash;
};
struct WorkPackage
{
WorkPackage() = default;
WorkPackage(Ethash::BlockHeader const& _bh):
boundary(_bh.boundary()),
headerHash(_bh.hashWithout()),
seedHash(_bh.seedHash())
{}
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
};
static const WorkPackage NullWorkPackage;
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
};
class EthashAux
{
public:
@ -46,7 +87,7 @@ public:
LightAllocation(h256 const& _seedHash);
~LightAllocation();
bytesConstRef data() const;
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
ethash_light_t light;
uint64_t size;
};
@ -55,7 +96,7 @@ public:
{
FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation();
Ethash::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t full;
@ -79,7 +120,7 @@ public:
/// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false.
static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function<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:
EthashAux() {}

6
libethcore/Farm.h

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

4
libethcore/Miner.h

@ -36,9 +36,9 @@ namespace dev
namespace eth
{
struct MineInfo: public MiningProgress {};
struct MineInfo: public WorkingProgress {};
inline std::ostream& operator<<(std::ostream& _out, MiningProgress _p)
inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p)
{
_out << _p.rate() << " H/s = " << _p.hashes << " hashes / " << (double(_p.ms) / 1000) << " s";
return _out;

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 <libdevcore/Guards.h>
#include <libdevcore/RLP.h>
#include "Common.h"
namespace dev
@ -34,28 +35,22 @@ namespace eth
class BlockInfo;
class SealFace
{
public:
virtual bool wouldSealHeader(BlockInfo const&) const { return true; }
virtual bytes sealedHeader(BlockInfo const& _bi) const = 0;
};
class SealEngineFace
{
public:
virtual std::string name() const = 0;
virtual unsigned revision() const = 0;
virtual unsigned sealFields() const = 0;
virtual bytes sealRLP() const = 0;
bytes option(std::string const& _name) const { Guard l(x_options); return m_options.count(_name) ? m_options.at(_name) : bytes(); }
bool setOption(std::string const& _name, bytes const& _value) { Guard l(x_options); try { if (onOptionChanging(_name, _value)) { m_options[_name] = _value; return true; } } catch (...) {} return false; }
virtual strings sealers() const { return { "default" }; }
virtual void setSealer(std::string const&) {}
virtual void generateSeal(BlockInfo const& _bi) = 0;
virtual void onSealGenerated(std::function<void(SealFace const* s)> const& _f) = 0;
virtual void disable() {}
// TODO: rename & generalise
virtual bool isMining() const { return false; }
virtual MiningProgress miningProgress() const { return MiningProgress(); }
virtual void onSealGenerated(std::function<void(bytes const& s)> const& _f) = 0;
virtual void cancelGeneration() {}
protected:
virtual bool onOptionChanging(std::string const&, bytes const&) { return true; }
@ -66,5 +61,15 @@ private:
std::unordered_map<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 <libethcore/Exceptions.h>
#include <libethcore/EthashAux.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h>
#include "GenesisInfo.h"
#include "State.h"
#include "Utility.h"
#include "Defaults.h"
using namespace std;
@ -48,7 +48,7 @@ using namespace dev;
using namespace dev::eth;
namespace js = json_spirit;
#define ETH_CATCH 1
#define ETH_CATCH 0
#define ETH_TIMED_IMPORTS 1
#ifdef _WIN32
@ -127,7 +127,8 @@ static const unsigned c_minCacheSize = 1024 * 1024 * 32;
#endif
BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, WithExisting _we, ProgressCallback const& _p)
BlockChain::BlockChain(bytes const& _genesisBlock, std::unordered_map<Address, Account> const& _genesisState, std::string const& _path, WithExisting _we, ProgressCallback const& _p):
m_genesisState(_genesisState)
{
// initialise deathrow.
m_cacheUsage.resize(c_collectionQueueSize);
@ -136,6 +137,10 @@ BlockChain::BlockChain(bytes const& _genesisBlock, std::string const& _path, Wit
// Initialise with the genesis as the last block on the longest chain.
m_genesisBlock = _genesisBlock;
m_genesisHash = sha3(RLP(m_genesisBlock)[0].data());
m_genesisState = _genesisState;
// remove the next line real soon. we don't need to be supporting this forever.
upgradeDatabase(_path, genesisHash());
if (open(_path, _we) != c_minorProtocolVersion)
rebuild(_path, _p);
@ -256,7 +261,7 @@ void BlockChain::rebuild(std::string const& _path, std::function<void(unsigned,
ldb::DB::Open(o, extrasPath + "/extras", &m_extrasDB);
// 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.
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);
BlockInfo bi(b);
BlockInfo bi(&b);
if (_prepPoW)
Ethash::prep(bi);
Ethash::ensurePrecomputed((unsigned)bi.number);
if (bi.parentHash != lastHash)
{
@ -351,7 +356,7 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
// Nonce & uncle nonces already verified in verification thread at this point.
ImportRoute r;
DEV_TIMED_ABOVE("Block import " + toString(block.verified.info.number), 500)
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles);
r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidSeal & ~ImportRequirements::CheckUncles);
fresh += r.liveBlocks;
dead += r.deadBlocks;
goodTransactions += r.goodTranactions;
@ -388,7 +393,7 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
{
try
{
return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir));
return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir));
}
catch (UnknownParent&)
{
@ -419,7 +424,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try
#endif
{
block = verifyBlock(_block, m_onBad, _ir);
block = verifyBlock(&_block, m_onBad, _ir);
}
#if ETH_CATCH
catch (Exception& ex)
@ -471,7 +476,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
auto parentBlock = block(_block.info.parentHash);
clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash);
clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number;
clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock);
clog(BlockChainDebug) << "Block:" << BlockInfo(&parentBlock);
clog(BlockChainDebug) << "RLP:" << RLP(parentBlock);
clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE";
exit(-1);
@ -509,7 +514,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
// Check transactions are valid and that they result in a state equivalent to our state_root.
// Get total difficulty increase and update state, checking it.
State s(_db);
auto tdIncrease = s.enactOn(_block, *this, _ir);
auto tdIncrease = s.enactOn(_block, *this);
for (unsigned i = 0; i < s.pending().size(); ++i)
{
@ -852,9 +857,9 @@ void BlockChain::rescue(OverlayDB& _db)
try
{
cout << "block..." << flush;
BlockInfo bi = info(h);
cout << "details..." << flush;
BlockDetails bd = details(h);
BlockInfo bi(block(h));
cout << "extras..." << flush;
details(h);
cout << "state..." << flush;
if (_db.exists(bi.stateRoot))
break;
@ -1189,69 +1194,58 @@ bytes BlockChain::block(h256 const& _hash) const
return m_blocks[_hash];
}
VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function<void(Exception&)> const& _onBad, ImportRequirements::value _ir)
bytes BlockChain::headerData(h256 const& _hash) const
{
VerifiedBlockRef res;
try
{
Strictness strictness = Strictness::CheckEverything;
if (~_ir & ImportRequirements::ValidNonce)
strictness = Strictness::IgnoreNonce;
if (_hash == m_genesisHash)
return BlockInfo::extractHeader(&m_genesisBlock).data().toBytes();
res.info.populate(_block, strictness);
res.info.verifyInternals(&_block);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
ReadGuard l(x_blocks);
auto it = m_blocks.find(_hash);
if (it != m_blocks.end())
return BlockInfo::extractHeader(&it->second).data().toBytes();
}
RLP r(_block);
unsigned i = 0;
for (auto const& uncle: r[2])
{
try
{
BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything);
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_uncleIndex(i);
ex << errinfo_now(time(0));
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
}
++i;
}
i = 0;
for (RLP const& tr: r[1])
string d;
m_blocksDB->Get(m_readOptions, toSlice(_hash), &d);
if (d.empty())
{
bytesConstRef d = tr.data();
try
{
res.transactions.push_back(Transaction(d, CheckTransaction::Everything));
}
catch (Exception& ex)
{
ex << errinfo_phase(1);
ex << errinfo_transactionIndex(i);
ex << errinfo_transaction(d.toBytes());
ex << errinfo_block(_block);
if (_onBad)
_onBad(ex);
throw;
}
++i;
cwarn << "Couldn't find requested block:" << _hash;
return bytes();
}
res.block = bytesConstRef(&_block);
return res;
noteUsed(_hash);
WriteGuard l(x_blocks);
m_blocks[_hash].resize(d.size());
memcpy(m_blocks[_hash].data(), d.data(), d.size());
return BlockInfo::extractHeader(&m_blocks[_hash]).data().toBytes();
}
State BlockChain::genesisState(OverlayDB const& _db)
{
State ret(_db, BaseState::Empty);
dev::eth::commit(m_genesisState, ret.m_state); // bit horrible. maybe consider a better way of constructing it?
ret.m_state.db()->commit(); // have to use this db() since it's the one that has been altered with the above commit.
ret.m_previousBlock = BlockInfo(&m_genesisBlock);
return ret;
}

113
libethereum/BlockChain.h

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

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

24
libethereum/BlockQueue.cpp

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

8
libethereum/BlockQueue.h

@ -76,11 +76,13 @@ public:
BlockQueue();
~BlockQueue();
void setChain(BlockChain const& _bc) { m_bc = &_bc; }
/// Import a block into the queue.
ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false);
ImportResult import(bytesConstRef _block, bool _isOurs = false);
/// Notes that time has moved on and some blocks that used to be "in the future" may no be valid.
void tick(BlockChain const& _bc);
void tick();
/// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain.
/// Don't forget to call doneDrain() once you're done importing.
@ -138,6 +140,8 @@ private:
void updateBad_WITH_LOCK(h256 const& _bad);
void drainVerified_WITH_BOTH_LOCKS();
BlockChain const* m_bc; ///< The blockchain into which our imports go.
mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown.
h256Hash m_drainingSet; ///< All blocks being imported.
h256Hash m_readySet; ///< All blocks ready for chain import.

75
libethereum/CanonBlockChain.cpp

@ -27,7 +27,6 @@
#include <libdevcore/RLP.h>
#include <libdevcore/FileSystem.h>
#include <libethcore/Exceptions.h>
#include <libethcore/ProofOfWork.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Params.h>
#include <liblll/Compiler.h>
@ -41,14 +40,44 @@ namespace js = json_spirit;
#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;
if (s_ret.empty())
{
js::mValue val;
json_spirit::read_string(c_genesisInfo, val);
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
for (auto account: val.get_obj())
{
u256 balance;
@ -68,53 +97,29 @@ std::unordered_map<Address, Account> const& dev::eth::genesisState()
return s_ret;
}
// TODO: place Registry in here.
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)
void CanonBlockChain<Ethash>::setGenesisState(std::string const& _json)
{
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);
s_nonce = _n;
s_genesis.reset();
}
BlockInfo const& CanonBlockChain::genesis()
Ethash::BlockHeader const& CanonBlockChain<Ethash>::genesis()
{
UpgradableGuard l(x_genesis);
if (!s_genesis)
{
auto gb = createGenesisBlock();
UpgradeGuard ul(l);
s_genesis.reset(new BlockInfo);
s_genesis->populate(&gb);
s_genesis.reset(new Ethash::BlockHeader);
s_genesis->populate(&gb, CheckEverything);
}
return *s_genesis;
}

45
libethereum/CanonBlockChain.h

@ -26,6 +26,7 @@
#include <libdevcore/Exceptions.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/Ethash.h>
#include <libdevcore/Guards.h>
#include "BlockDetails.h"
#include "Account.h"
@ -45,7 +46,32 @@ std::unordered_map<Address, Account> const& genesisState();
* @threadsafe
* @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:
CanonBlockChain(WithExisting _we = WithExisting::Trust, ProgressCallback const& _pc = ProgressCallback()): CanonBlockChain(std::string(), _we, _pc) {}
@ -53,22 +79,35 @@ public:
~CanonBlockChain() {}
/// @returns the genesis block header.
static BlockInfo const& genesis();
static Ethash::BlockHeader const& genesis();
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static bytes createGenesisBlock();
/// @returns the genesis block as its RLP-encoded byte array.
/// @note This is slow as it's constructed anew each call. Consider genesis() instead.
static std::unordered_map<Address, Account> createGenesisState();
/// Alter the value of the genesis block's nonce.
/// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all.
static void setGenesisNonce(Nonce const& _n);
/// Alter all the genesis block's state by giving a JSON string with account details.
/// @TODO implement.
/// @warning Unless you're very careful, make sure you call this right at the start of the
/// program, before anything has had the chance to use this class at all.
static void setGenesisState(std::string const&);
// TODO: setGenesisTimestamp, ...ExtraData, ...Difficulty, ...GasLimit,
private:
/// Static genesis info and its lock.
static boost::shared_mutex x_genesis;
static std::unique_ptr<BlockInfo> s_genesis;
static std::unique_ptr<Ethash::BlockHeader> s_genesis;
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
};
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):
Client(_extNet, make_shared<TrivialGasPricer>(), _dbPath, _forceAction, _networkId)
void Client::init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId)
{
startWorking();
}
// Cannot be opened until after blockchain is open, since BlockChain may upgrade the database.
// TODO: consider returning the upgrade mechanism here. will delaying the opening of the blockchain database
// until after the construction.
m_stateDB = State::openDB(_dbPath, bc().genesisHash(), _forceAction);
m_preMine = State(m_stateDB);
m_postMine = State(m_stateDB);
// LAZY. TODO: move genesis state construction/commiting to stateDB openning and have this just take the root from the genesis block.
m_preMine = bc().genesisState(m_stateDB);
Client::Client(p2p::Host* _extNet, std::shared_ptr<GasPricer> _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId):
Worker("eth", 0),
m_vc(_dbPath),
m_bc(_dbPath, _forceAction, [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }),
m_gp(_gp),
m_stateDB(State::openDB(_dbPath, _forceAction)),
m_preMine(m_stateDB, BaseState::CanonGenesis),
m_postMine(m_stateDB)
{
if (_forceAction == WithExisting::Rescue)
m_bc.rescue(m_stateDB);
m_bq.setChain(bc());
m_lastGetWork = std::chrono::system_clock::now() - chrono::seconds(30);
m_tqReady = m_tq.onReady([=](){ this->onTransactionQueueReady(); }); // TODO: should read m_tq->onReady(thisThread, syncTransactionQueue);
m_bqReady = m_bq.onReady([=](){ this->onBlockQueueReady(); }); // TODO: should read m_bq->onReady(thisThread, syncBlockQueue);
m_bq.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_bc.setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_sealEngine = shared_ptr<SealEngineFace>(Ethash::createSealEngine());
m_sealEngine->onSolutionFound([=](Ethash::Solution const& s){ return this->submitWork(s); });
bc().setOnBad([=](Exception& ex){ this->onBadBlock(ex); });
m_gp->update(m_bc);
if (_forceAction == WithExisting::Rescue)
m_bc.rescue(m_stateDB);
m_gp->update(bc());
auto host = _extNet->registerCapability(new EthereumHost(m_bc, m_tq, m_bq, _networkId));
auto host = _extNet->registerCapability(new EthereumHost(bc(), m_tq, m_bq, _networkId));
m_host = host;
_extNet->addCapability(host, EthereumHost::staticName(), EthereumHost::c_oldProtocolVersion); //TODO: remove this one v61+ protocol is common
if (_dbPath.size())
Defaults::setDBPath(_dbPath);
doWork();
startWorking();
}
@ -125,13 +121,13 @@ ImportResult Client::queueBlock(bytes const& _block, bool _isSafe)
{
if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 10000)
this_thread::sleep_for(std::chrono::milliseconds(500));
return m_bq.import(&_block, bc(), _isSafe);
return m_bq.import(&_block, _isSafe);
}
tuple<ImportRoute, bool, unsigned> Client::syncQueue(unsigned _max)
{
stopWorking();
return m_bc.sync(m_bq, m_stateDB, _max);
return bc().sync(m_bq, m_stateDB, _max);
}
void Client::onBadBlock(Exception& _ex) const
@ -294,7 +290,7 @@ void Client::startedWorking()
clog(ClientTrace) << "startedWorking()";
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine)
{
DEV_WRITE_GUARDED(x_working)
@ -309,7 +305,7 @@ void Client::doneWorking()
// Synchronise the state according to the head of the block chain.
// TODO: currently it contains keys for *all* blocks. Make it remove old ones.
DEV_WRITE_GUARDED(x_preMine)
m_preMine.sync(m_bc);
m_preMine.sync(bc());
DEV_READ_GUARDED(x_preMine)
{
DEV_WRITE_GUARDED(x_working)
@ -328,7 +324,7 @@ void Client::killChain()
m_tq.clear();
m_bq.clear();
m_farm.disable();
m_sealEngine->cancelGeneration();
{
WriteGuard l(x_postMine);
@ -340,10 +336,10 @@ void Client::killChain()
m_working = State();
m_stateDB = OverlayDB();
m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill);
m_bc.reopen(Defaults::dbPath(), WithExisting::Kill);
m_stateDB = State::openDB(Defaults::dbPath(), bc().genesisHash(), WithExisting::Kill);
bc().reopen(Defaults::dbPath(), WithExisting::Kill);
m_preMine = State(m_stateDB, BaseState::CanonGenesis);
m_preMine = bc().genesisState(m_stateDB);
m_postMine = State(m_stateDB);
}
@ -415,8 +411,8 @@ void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash&
void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed)
{
// TODO: more precise check on whether the txs match.
auto d = m_bc.info(_block);
auto receipts = m_bc.receipts(_block).receipts;
auto d = bc().info(_block);
auto receipts = bc().receipts(_block).receipts;
Guard l(x_filtersWatches);
io_changed.insert(ChainChangedFilter);
@ -449,17 +445,22 @@ void Client::setForceMining(bool _enable)
startMining();
}
MiningProgress Client::miningProgress() const
bool Client::isMining() const
{
if (m_farm.isMining())
return m_farm.miningProgress();
return MiningProgress();
return Ethash::isWorking(m_sealEngine.get());
}
WorkingProgress Client::miningProgress() const
{
if (Ethash::isWorking(m_sealEngine.get()))
return Ethash::workingProgress(m_sealEngine.get());
return WorkingProgress();
}
uint64_t Client::hashrate() const
{
if (m_farm.isMining())
return m_farm.miningProgress().rate();
if (Ethash::isWorking(m_sealEngine.get()))
return Ethash::workingProgress(m_sealEngine.get()).rate();
return 0;
}
@ -504,45 +505,6 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
return ret;
}
ProofOfWork::WorkPackage Client::getWork()
{
// lock the work so a later submission isn't invalidated by processing a transaction elsewhere.
// this will be reset as soon as a new block arrives, allowing more transactions to be processed.
bool oldShould = shouldServeWork();
m_lastGetWork = chrono::system_clock::now();
if (!m_mineOnBadChain && isChainBad())
return ProofOfWork::WorkPackage();
// if this request has made us bother to serve work, prep it now.
if (!oldShould && shouldServeWork())
onPostStateChanged();
else
// otherwise, set this to true so that it gets prepped next time.
m_remoteWorking = true;
return ProofOfWork::package(m_miningInfo);
}
bool Client::submitWork(ProofOfWork::Solution const& _solution)
{
bytes newBlock;
DEV_WRITE_GUARDED(x_working)
if (!m_working.completeMine<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_syncMax = 1000;
double static const c_targetDuration = 1;
@ -553,7 +515,7 @@ void Client::syncBlockQueue()
ImportRoute ir;
unsigned count;
Timer t;
tie(ir, m_syncBlockQueue, count) = m_bc.sync(m_bq, m_stateDB, m_syncAmount);
tie(ir, m_syncBlockQueue, count) = bc().sync(m_bq, m_stateDB, m_syncAmount);
double elapsed = t.elapsed();
if (count)
@ -577,7 +539,7 @@ void Client::syncTransactionQueue()
TransactionReceipts newPendingReceipts;
DEV_WRITE_GUARDED(x_working)
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(m_bc, m_tq, *m_gp);
tie(newPendingReceipts, m_syncTransactionQueue) = m_working.sync(bc(), m_tq, *m_gp);
if (newPendingReceipts.empty())
return;
@ -590,7 +552,7 @@ void Client::syncTransactionQueue()
for (size_t i = 0; i < newPendingReceipts.size(); i++)
appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3());
// Tell farm about new transaction (i.e. restartProofOfWork mining).
// Tell farm about new transaction (i.e. restart mining).
onPostStateChanged();
// Tell watches about the new transactions.
@ -607,7 +569,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
for (auto const& h: _ir.deadBlocks)
{
clog(ClientTrace) << "Dead block:" << h;
for (auto const& t: m_bc.transactions(h))
for (auto const& t: bc().transactions(h))
{
clog(ClientTrace) << "Resubmitting dead-block transaction " << Transaction(t, CheckTransaction::None);
m_tq.import(t, IfDropped::Retry);
@ -641,7 +603,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
newPreMine = m_preMine;
// TODO: use m_postMine to avoid re-evaluating our own blocks.
preChanged = newPreMine.sync(m_bc);
preChanged = newPreMine.sync(bc());
if (preChanged || m_postMine.address() != m_preMine.address())
{
@ -700,7 +662,7 @@ void Client::rejigMining()
{
clog(ClientTrace) << "Rejigging mining...";
DEV_WRITE_GUARDED(x_working)
m_working.commitToMine(m_bc, m_extraData);
m_working.commitToMine(bc(), m_extraData);
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
@ -709,10 +671,10 @@ void Client::rejigMining()
}
if (m_wouldMine)
m_farm.sealBlock(m_miningInfo);
m_sealEngine->generateSeal(m_miningInfo);
}
if (!m_wouldMine)
m_farm.disable();
m_sealEngine->cancelGeneration();
}
void Client::noteChanged(h256Hash const& _filters)
@ -768,7 +730,7 @@ void Client::tick()
{
m_report.ticks++;
checkWatchGarbage();
m_bq.tick(m_bc);
m_bq.tick();
m_lastTick = chrono::system_clock::now();
if (m_report.ticks == 15)
clog(ClientTrace) << activityReport();
@ -792,7 +754,7 @@ void Client::checkWatchGarbage()
uninstallWatch(i);
// blockchain GC
m_bc.garbageCollect();
bc().garbageCollect();
m_lastGarbageCollection = chrono::system_clock::now();
}
@ -824,7 +786,7 @@ State Client::state(unsigned _txi, h256 _block) const
try
{
State ret(m_stateDB);
ret.populateFromChain(m_bc, _block);
ret.populateFromChain(bc(), _block);
return ret.fromPending(_txi);
}
catch (Exception& ex)
@ -840,7 +802,7 @@ State Client::state(h256 const& _block, PopulationStatistics* o_stats) const
try
{
State ret(m_stateDB);
PopulationStatistics s = ret.populateFromChain(m_bc, _block);
PopulationStatistics s = ret.populateFromChain(bc(), _block);
if (o_stats)
swap(s, *o_stats);
return ret;
@ -871,3 +833,61 @@ SyncStatus Client::syncStatus() const
auto h = m_host.lock();
return h ? h->status() : SyncStatus();
}
bool Client::submitSealed(bytes const& _header)
{
DEV_WRITE_GUARDED(x_working)
if (!m_working.sealBlock(_header))
return false;
bytes newBlock;
DEV_READ_GUARDED(x_working)
{
DEV_WRITE_GUARDED(x_postMine)
m_postMine = m_working;
newBlock = m_working.blockData();
}
// OPTIMISE: very inefficient to not utilise the existing OverlayDB in m_postMine that contains all trie changes.
return m_bq.import(&newBlock, true) == ImportResult::Success;
}
std::tuple<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
};
class VersionChecker
{
public:
VersionChecker(std::string const& _dbPath);
};
struct ClientNote: public LogChannel { static const char* name(); static const int verbosity = 2; };
struct ClientChat: public LogChannel { static const char* name(); static const int verbosity = 4; };
struct ClientTrace: public LogChannel { static const char* name(); static const int verbosity = 7; };
@ -81,25 +75,14 @@ std::ostream& operator<<(std::ostream& _out, ActivityReport const& _r);
/**
* @brief Main API hub for interfacing with Ethereum.
* Not to be used directly - subclass.
*/
class Client: public ClientBase, Worker
{
public:
/// New-style Constructor.
explicit Client(
p2p::Host* _host,
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
explicit Client(
p2p::Host* _host,
std::shared_ptr<GasPricer> _gpForAdoption, // pass it in with new.
std::string const& _dbPath = std::string(),
WithExisting _forceAction = WithExisting::Trust,
u256 _networkId = 0
);
/// Any final derived class's constructor should make sure they call init().
explicit Client(std::shared_ptr<GasPricer> _gpForAdoption);
/// Destructor.
virtual ~Client();
@ -129,7 +112,7 @@ public:
/// Get the object representing the current state of Ethereum.
dev::eth::State postState() const { ReadGuard l(x_postMine); return m_postMine; }
/// Get the object representing the current canonical blockchain.
CanonBlockChain const& blockChain() const { return m_bc; }
BlockChain const& blockChain() const { return bc(); }
/// Get some information on the block queue.
BlockQueueStatus blockQueueStatus() const { return m_bq.status(); }
/// Get some information on the block queue.
@ -176,26 +159,16 @@ public:
/// NOT thread-safe
void stopMining() override { m_wouldMine = false; rejigMining(); }
/// Are we mining now?
bool isMining() const override { return m_farm.isMining(); }
bool isMining() const override;
/// Are we mining now?
bool wouldMine() const override { return m_wouldMine; }
/// The hashrate...
uint64_t hashrate() const override;
/// Check the progress of the mining.
MiningProgress miningProgress() const override;
WorkingProgress miningProgress() const override;
/// Get and clear the mining history.
std::list<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:
DownloadMan const* downloadMan() const;
@ -218,12 +191,20 @@ public:
/// Set the extra data that goes into mined blocks.
void setExtraData(bytes const& _extraData) { m_extraData = _extraData; }
/// Rewind to a prior head.
void rewind(unsigned _n) { m_bc.rewind(_n); }
void rewind(unsigned _n) { bc().rewind(_n); }
/// Rescue the chain.
void rescue() { bc().rescue(m_stateDB); }
/// Get the seal engine.
SealEngineFace* sealEngine() const { return m_sealEngine.get(); }
protected:
/// Perform critical setup functions.
/// Must be called in the constructor of the finally derived class.
void init(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId);
/// InterfaceStub methods
virtual BlockChain& bc() override { return m_bc; }
virtual BlockChain const& bc() const override { return m_bc; }
virtual BlockChain& bc() override = 0;
virtual BlockChain const& bc() const override = 0;
/// Returns the state object for the full block (i.e. the terminal state) for index _h.
/// Works properly with LatestBlock and PendingBlock.
@ -245,7 +226,10 @@ protected:
/// This doesn't actually make any callbacks, but incrememnts some counters in m_watches.
void noteChanged(h256Hash const& _filters);
private:
/// Submit
bool submitSealed(bytes const& _s);
protected:
/// Called when Worker is starting.
void startedWorking() override;
@ -291,8 +275,6 @@ private:
/// @warning May be called from any thread.
void onBadBlock(Exception& _ex) const;
VersionChecker m_vc; ///< Dummy object to check & update the protocol version.
CanonBlockChain m_bc; ///< Maintains block database.
BlockQueue m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported).
std::shared_ptr<GasPricer> m_gp; ///< The gas pricer.
@ -339,5 +321,64 @@ private:
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);
RLP b(bl);
if (_i < b[2].itemCount())
return BlockInfo::fromHeader(b[2][_i].data());
return BlockInfo(b[2][_i].data(), CheckNothing, h256(), HeaderData);
else
return BlockInfo();
}

4
libethereum/ClientBase.h

@ -156,9 +156,7 @@ public:
virtual bool isMining() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::isMining")); }
virtual bool wouldMine() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::wouldMine")); }
virtual uint64_t hashrate() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::hashrate")); }
virtual MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); }
virtual bool submitWork(ProofOfWork::Solution const&) override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::submitWork")); }
virtual WorkingProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); }
State asOf(BlockNumber _h) const;

8
libethereum/Interface.h

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

87
libethereum/State.cpp

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

66
libethereum/State.h

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

4
libethereum/Utility.cpp

@ -91,7 +91,7 @@ bytes dev::eth::parseData(string const& _args)
return m_data;
}
void dev::eth::upgradeDatabase(std::string const& _basePath)
void dev::eth::upgradeDatabase(std::string const& _basePath, h256 const& _genesisHash)
{
std::string path = _basePath.empty() ? Defaults::get()->dbPath() : _basePath;
@ -105,7 +105,7 @@ void dev::eth::upgradeDatabase(std::string const& _basePath)
{
auto minorProtocolVersion = (unsigned)status[1];
auto databaseVersion = (unsigned)status[2];
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : CanonBlockChain::genesis().hash();
auto genesisHash = status.itemCount() > 3 ? (h256)status[3] : _genesisHash;
string chainPath = path + "/" + toHex(genesisHash.ref().cropped(0, 4));
string extrasPath = chainPath + "/" + toString(databaseVersion);

3
libethereum/Utility.h

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

6
libweb3jsonrpc/JsonHelper.cpp

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

14
libweb3jsonrpc/JsonHelper.h

@ -23,6 +23,7 @@
#include <json/json.h>
#include <libethcore/Common.h>
#include <libethcore/BlockInfo.h>
#include <libethereum/LogFilter.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, 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

3
test/libethcore/dagger.cpp

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

3
test/libethereum/stateOriginal.cpp

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

Loading…
Cancel
Save