diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 3f3d1e237..8e48793c9 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -180,6 +180,7 @@
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 2e4478594..a60875ba6 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1752,6 +1752,11 @@ void Main::on_clearPending_triggered()
refreshAll();
}
+void Main::on_retryUnknown_triggered()
+{
+ ethereum()->retryUnkonwn();
+}
+
void Main::on_killBlockchain_triggered()
{
writeSettings();
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index a5c74eeaa..a8579ed01 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -163,6 +163,7 @@ private slots:
void on_usePrivate_triggered();
void on_turboMining_triggered();
void on_jitvm_triggered();
+ void on_retryUnknown_triggered();
// Debugger
void on_debugCurrent_triggered();
diff --git a/eth/main.cpp b/eth/main.cpp
index 24bf839aa..461494cef 100644
--- a/eth/main.cpp
+++ b/eth/main.cpp
@@ -32,11 +32,12 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
#include
-#include
#if ETH_READLINE
#include
#include
@@ -111,6 +112,7 @@ void help()
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (Default: 15)." << endl
<< " -c,--client-name Add a name to your client's version string (default: blank)." << endl
+ << " -C,--check-pow Check PoW credentials for validity." << endl
<< " -d,--db-path Load database from path (default: ~/.ethereum " << endl
<< " /Etherum or Library/Application Support/Ethereum)." << endl
<< " -D,--create-dag Create the DAG in preparation for mining on given block and exit." << endl
@@ -401,6 +403,43 @@ int main(int argc, char** argv)
return -1;
}
}
+ else if ((arg == "-C" || arg == "--check-pow") && i + 4 < argc)
+ {
+ string m;
+ try
+ {
+ BlockInfo bi;
+ m = boost::to_lower_copy(string(argv[++i]));
+ h256 powHash(m);
+ m = boost::to_lower_copy(string(argv[++i]));
+ h256 seedHash;
+ if (m.size() == 64 || m.size() == 66)
+ seedHash = h256(m);
+ else
+ seedHash = EthashAux::seedHash(stol(m));
+ m = boost::to_lower_copy(string(argv[++i]));
+ bi.difficulty = u256(m);
+ auto boundary = bi.boundary();
+ m = boost::to_lower_copy(string(argv[++i]));
+ bi.nonce = h64(m);
+ auto r = EthashAux::eval(seedHash, powHash, bi.nonce);
+ bool valid = r.value < boundary;
+ cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
+ cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
+ cout << " where " << boundary << " = 2^256 / " << bi.difficulty << endl;
+ cout << " and " << r.value << " = ethash(" << powHash << ", " << bi.nonce << ")" << endl;
+ cout << " with seed as " << seedHash << endl;
+ if (valid)
+ cout << "(mixHash = " << r.mixHash << ")" << endl;
+ cout << "SHA3( light(seed) ) = " << sha3(bytesConstRef((byte const*)EthashAux::light(seedHash), EthashAux::params(seedHash).cache_size)) << endl;
+ exit(0);
+ }
+ catch (...)
+ {
+ cerr << "Bad " << arg << " option: " << m << endl;
+ return -1;
+ }
+ }
else if ((arg == "-B" || arg == "--block-fees") && i + 1 < argc)
{
try
diff --git a/libdevcore/Guards.h b/libdevcore/Guards.h
index f5c64b041..4229428ce 100644
--- a/libdevcore/Guards.h
+++ b/libdevcore/Guards.h
@@ -38,4 +38,75 @@ using UpgradableGuard = boost::upgrade_lock;
using UpgradeGuard = boost::upgrade_to_unique_lock;
using WriteGuard = boost::unique_lock;
+template
+struct GenericGuardBool: GuardType
+{
+ GenericGuardBool(MutexType& _m): GuardType(_m) {}
+ bool b = true;
+};
+template
+struct GenericUnguardBool
+{
+ GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); }
+ ~GenericUnguardBool() { m.lock(); }
+ bool b = true;
+ MutexType& m;
+};
+template
+struct GenericUnguardSharedBool
+{
+ GenericUnguardSharedBool(MutexType& _m): m(_m) { m.unlock_shared(); }
+ ~GenericUnguardSharedBool() { m.lock_shared(); }
+ bool b = true;
+ MutexType& m;
+};
+
+/** @brief Simple block guard.
+ * The expression/block following is guarded though the given mutex.
+ * Usage:
+ * @code
+ * Mutex m;
+ * unsigned d;
+ * ...
+ * ETH_GUARDED(m) d = 1;
+ * ...
+ * ETH_GUARDED(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
+ * @endcode
+ *
+ * There are several variants of this basic mechanism for different Mutex types and Guards.
+ *
+ * There is also the UNGUARD variant which allows an unguarded expression/block to exist within a
+ * guarded expression. eg:
+ *
+ * @code
+ * Mutex m;
+ * int d;
+ * ...
+ * ETH_GUARDED(m)
+ * {
+ * for (auto d = 50; d > 25; --d)
+ * foo(d);
+ * ETH_UNGUARDED(m)
+ * bar();
+ * for (; d > 0; --d)
+ * foo(d);
+ * }
+ * @endcode
+ */
+
+#define ETH_GUARDED(MUTEX) \
+ for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_READ_GUARDED(MUTEX) \
+ for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_WRITE_GUARDED(MUTEX) \
+ for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_RECURSIVE_GUARDED(MUTEX) \
+ for (GenericGuardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_UNGUARDED(MUTEX) \
+ for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_READ_UNGUARDED(MUTEX) \
+ for (GenericUnguardSharedBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+#define ETH_WRITE_UNGUARDED(MUTEX) \
+ for (GenericUnguardBool __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
+
}
diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp
index fb4c2820d..061af566e 100644
--- a/libethcore/EthashAux.cpp
+++ b/libethcore/EthashAux.cpp
@@ -67,19 +67,24 @@ h256 EthashAux::seedHash(unsigned _number)
{
unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
RecursiveGuard l(get()->x_this);
- if (_number < get()->m_seedHashes.size())
- return get()->m_seedHashes[_number];
- h256 ret;
- unsigned n = 0;
- if (!get()->m_seedHashes.empty())
+ if (epoch >= get()->m_seedHashes.size())
{
- ret = get()->m_seedHashes.back();
- n = get()->m_seedHashes.size() - 1;
+ h256 ret;
+ unsigned n = 0;
+ if (!get()->m_seedHashes.empty())
+ {
+ ret = get()->m_seedHashes.back();
+ n = get()->m_seedHashes.size() - 1;
+ }
+ get()->m_seedHashes.resize(epoch + 1);
+ cdebug << "Searching for seedHash of epoch " << epoch;
+ for (; n <= epoch; ++n, ret = sha3(ret))
+ {
+ get()->m_seedHashes[n] = ret;
+ cdebug << "Epoch" << n << "is" << ret.abridged();
+ }
}
- cdebug << "Searching for seedHash of epoch " << epoch;
- for (; n < epoch; ++n, ret = sha3(ret))
- cdebug << "Epoch" << n << "is" << ret.abridged();
- return ret;
+ return get()->m_seedHashes[epoch];
}
ethash_params EthashAux::params(h256 const& _seedHash)
@@ -93,17 +98,13 @@ ethash_params EthashAux::params(h256 const& _seedHash)
catch (...)
{
cdebug << "Searching for seedHash " << _seedHash.abridged();
- for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h))
- {
- cdebug << "Epoch" << epoch << "is" << h.abridged();
- }
+ for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
if (epoch == 2048)
{
std::ostringstream error;
error << "apparent block number for " << _seedHash.abridged() << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
throw std::invalid_argument(error.str());
}
- get()->m_epochs[_seedHash] = epoch;
}
return params(epoch * ETHASH_EPOCH_LENGTH);
}
diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h
index 94c2243e0..c927a012b 100644
--- a/libethcore/EthashAux.h
+++ b/libethcore/EthashAux.h
@@ -41,7 +41,7 @@ public:
static ethash_params params(h256 const& _seedHash);
static ethash_params params(unsigned _n);
static LightType light(BlockInfo const& _header);
- static LightType light(h256 const& _header);
+ static LightType light(h256 const& _seedHash);
static bytesConstRef full(BlockInfo const& _header, bytesRef _dest = bytesRef());
static bytesConstRef full(h256 const& _header, bytesRef _dest = bytesRef());
diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp
index 029f8b47a..655c8a78b 100644
--- a/libethcore/Params.cpp
+++ b/libethcore/Params.cpp
@@ -30,7 +30,6 @@ namespace eth
//--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json
u256 const c_genesisDifficulty = 131072;
u256 const c_maximumExtraDataSize = 1024;
-u256 const c_epochDuration = 30000;
u256 const c_genesisGasLimit = 3141592;
u256 const c_minGasLimit = 125000;
u256 const c_gasLimitBoundDivisor = 1024;
diff --git a/libethcore/Params.h b/libethcore/Params.h
index 46b30e2c3..b957f9737 100644
--- a/libethcore/Params.h
+++ b/libethcore/Params.h
@@ -37,7 +37,6 @@ extern u256 const c_minimumDifficulty;
extern u256 const c_difficultyBoundDivisor;
extern u256 const c_durationLimit;
extern u256 const c_maximumExtraDataSize;
-extern u256 const c_epochDuration;
extern u256 const c_stackLimit;
extern u256 const c_tierStepGas[8]; ///< Once per operation, for a selection of them.
diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp
index e9dd99cd1..b76e4bed6 100644
--- a/libethereum/BlockQueue.cpp
+++ b/libethereum/BlockQueue.cpp
@@ -183,3 +183,15 @@ void BlockQueue::noteReadyWithoutWriteGuard(h256 _good)
m_unknown.erase(r.first, r.second);
}
}
+
+void BlockQueue::retryAllUnknown()
+{
+ for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it)
+ {
+ m_ready.push_back(it->second.second);
+ auto newReady = it->second.first;
+ m_unknownSet.erase(newReady);
+ m_readySet.insert(newReady);
+ }
+ m_unknown.clear();
+}
diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h
index f5cdf7ab5..4a503d114 100644
--- a/libethereum/BlockQueue.h
+++ b/libethereum/BlockQueue.h
@@ -71,6 +71,9 @@ public:
/// Notify the queue that the chain has changed and a new block has attained 'ready' status (i.e. is in the chain).
void noteReady(h256 _b) { WriteGuard l(m_lock); noteReadyWithoutWriteGuard(_b); }
+ /// Force a retry of all the blocks with unknown parents.
+ void retryAllUnknown();
+
/// Get information on the items queued.
std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index c99b13425..0660b6cee 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -436,15 +436,12 @@ void Client::syncBlockQueue()
{
ImportRoute ir;
+ cwork << "BQ ==> CHAIN ==> STATE";
{
WriteGuard l(x_stateDB);
- cwork << "BQ ==> CHAIN ==> STATE";
OverlayDB db = m_stateDB;
- x_stateDB.unlock();
-
- tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100);
-
- x_stateDB.lock();
+ ETH_WRITE_UNGUARDED(x_stateDB)
+ tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100);
if (ir.first.empty())
return;
m_stateDB = db;
@@ -458,7 +455,11 @@ void Client::syncTransactionQueue()
cwork << "postSTATE <== TQ";
h256Set changeds;
- TransactionReceipts newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
+ TransactionReceipts newPendingReceipts;
+
+ ETH_WRITE_GUARDED(x_stateDB)
+ newPendingReceipts = m_postMine.sync(m_bc, m_tq, *m_gp);
+
if (newPendingReceipts.size())
{
for (size_t i = 0; i < newPendingReceipts.size(); i++)
@@ -512,8 +513,7 @@ void Client::onChainChanged(ImportRoute const& _ir)
// RESTART MINING
// LOCKS REALLY NEEDED?
- {
- ReadGuard l(x_stateDB);
+ ETH_WRITE_GUARDED(x_stateDB)
if (m_preMine.sync(m_bc) || m_postMine.address() != m_preMine.address())
{
if (isMining())
@@ -522,11 +522,9 @@ void Client::onChainChanged(ImportRoute const& _ir)
m_postMine = m_preMine;
changeds.insert(PendingChangedFilter);
- x_stateDB.unlock_shared();
- onPostStateChanged();
- x_stateDB.lock_shared();
+ ETH_WRITE_UNGUARDED(x_stateDB)
+ onPostStateChanged();
}
- }
noteChanged(changeds);
}
@@ -534,17 +532,24 @@ void Client::onChainChanged(ImportRoute const& _ir)
void Client::onPostStateChanged()
{
cnote << "Post state changed: Restarting mining...";
+ if (isMining())
{
- WriteGuard l(x_stateDB);
- cdebug << "Pre:" << m_preMine.info();
- m_postMine.commitToMine(m_bc);
- m_miningInfo = m_postMine.info();
- cdebug << "Pre:" << m_preMine.info();
- cdebug << "Post:" << m_postMine.info();
- cdebug << "Pre:" << m_preMine.info().headerHash(WithoutNonce) << "; Post:" << m_postMine.info().headerHash(WithoutNonce);
+ {
+ WriteGuard l(x_stateDB);
+ m_postMine.commitToMine(m_bc);
+ m_miningInfo = m_postMine.info();
+ }
+ m_farm.setWork(m_miningInfo);
}
+}
- m_farm.setWork(m_miningInfo);
+void Client::startMining()
+{
+ if (m_turboMining)
+ m_farm.startGPU();
+ else
+ m_farm.startCPU();
+ onPostStateChanged();
}
void Client::noteChanged(h256Set const& _filters)
diff --git a/libethereum/Client.h b/libethereum/Client.h
index 289df3fe0..dedb3bcf1 100644
--- a/libethereum/Client.h
+++ b/libethereum/Client.h
@@ -169,7 +169,7 @@ public:
/// Start mining.
/// NOT thread-safe - call it & stopMining only from a single thread
- void startMining() override { if (m_turboMining) m_farm.startGPU(); else m_farm.startCPU(); onPostStateChanged(); }
+ void startMining() override;
/// Stop mining.
/// NOT thread-safe
void stopMining() override { m_farm.stop(); }
@@ -202,6 +202,8 @@ public:
void clearPending();
/// Kills the blockchain. Just for debug use.
void killChain();
+ /// Retries all blocks with unknown parents.
+ void retryUnkonwn() { m_bq.retryAllUnknown(); }
protected:
/// InterfaceStub methods
diff --git a/libethereum/Farm.h b/libethereum/Farm.h
index afca853ed..26d4b139e 100644
--- a/libethereum/Farm.h
+++ b/libethereum/Farm.h
@@ -92,11 +92,12 @@ public:
WriteGuard l(x_minerWork);
m_miners.clear();
m_work.reset();
+ m_isMining = false;
}
bool isMining() const
{
- return !!m_work;
+ return m_isMining;
}
/**
@@ -165,6 +166,7 @@ private:
m_miners.push_back(std::shared_ptr(new MinerType(std::make_pair(this, i))));
m_miners.back()->setWork(m_work);
}
+ m_isMining = true;
resetTimer();
return true;
}
@@ -179,6 +181,8 @@ private:
WorkPackage m_work;
BlockInfo m_header;
+ std::atomic m_isMining = {false};
+
mutable SharedMutex x_progress;
mutable MiningProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart;