Browse Source

Fix to ethash seedHash caching.

cl-refactor
Gav Wood 10 years ago
parent
commit
8e3ef1ee5c
  1. 6
      alethzero/Main.ui
  2. 5
      alethzero/MainWin.cpp
  3. 1
      alethzero/MainWin.h
  4. 41
      eth/main.cpp
  5. 71
      libdevcore/Guards.h
  6. 19
      libethcore/EthashAux.cpp
  7. 2
      libethcore/EthashAux.h
  8. 1
      libethcore/Params.cpp
  9. 1
      libethcore/Params.h
  10. 12
      libethereum/BlockQueue.cpp
  11. 3
      libethereum/BlockQueue.h
  12. 37
      libethereum/Client.cpp
  13. 4
      libethereum/Client.h
  14. 6
      libethereum/Farm.h

6
alethzero/Main.ui

@ -180,6 +180,7 @@
<addaction name="separator"/>
<addaction name="usePrivate"/>
<addaction name="jitvm"/>
<addaction name="retryUnknown"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
@ -1679,6 +1680,11 @@ font-size: 14pt</string>
<string>&amp;GPU Mining</string>
</property>
</action>
<action name="retryUnknown">
<property name="text">
<string>Retry Unknown Parent Blocks</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

5
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();

1
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();

41
eth/main.cpp

@ -32,11 +32,12 @@
#include <libdevcrypto/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>
#include <libethereum/All.h>
#include <libwebthree/WebThree.h>
#include <libethcore/ProofOfWork.h>
#if ETH_READLINE
#include <readline/readline.h>
#include <readline/history.h>
@ -111,6 +112,7 @@ void help()
<< " -b,--bootstrap Connect to the default Ethereum peerserver." << endl
<< " -B,--block-fees <n> Set the block fee profit in the reference unit e.g. ¢ (Default: 15)." << endl
<< " -c,--client-name <name> Add a name to your client's version string (default: blank)." << endl
<< " -C,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
<< " -d,--db-path <path> Load database from path (default: ~/.ethereum " << endl
<< " <APPDATA>/Etherum or Library/Application Support/Ethereum)." << endl
<< " -D,--create-dag <this/next/number> 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

71
libdevcore/Guards.h

@ -38,4 +38,75 @@ using UpgradableGuard = boost::upgrade_lock<boost::shared_mutex>;
using UpgradeGuard = boost::upgrade_to_unique_lock<boost::shared_mutex>;
using WriteGuard = boost::unique_lock<boost::shared_mutex>;
template <class GuardType, class MutexType>
struct GenericGuardBool: GuardType
{
GenericGuardBool(MutexType& _m): GuardType(_m) {}
bool b = true;
};
template <class MutexType>
struct GenericUnguardBool
{
GenericUnguardBool(MutexType& _m): m(_m) { m.unlock(); }
~GenericUnguardBool() { m.lock(); }
bool b = true;
MutexType& m;
};
template <class MutexType>
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<Guard, Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_GUARDED(MUTEX) \
for (GenericGuardBool<ReadGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_GUARDED(MUTEX) \
for (GenericGuardBool<WriteGuard, SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_RECURSIVE_GUARDED(MUTEX) \
for (GenericGuardBool<RecursiveGuard, RecursiveMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_UNGUARDED(MUTEX) \
for (GenericUnguardBool<Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_READ_UNGUARDED(MUTEX) \
for (GenericUnguardSharedBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
#define ETH_WRITE_UNGUARDED(MUTEX) \
for (GenericUnguardBool<SharedMutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
}

19
libethcore/EthashAux.cpp

@ -67,8 +67,8 @@ 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];
if (epoch >= get()->m_seedHashes.size())
{
h256 ret;
unsigned n = 0;
if (!get()->m_seedHashes.empty())
@ -76,10 +76,15 @@ h256 EthashAux::seedHash(unsigned _number)
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))
for (; n <= epoch; ++n, ret = sha3(ret))
{
get()->m_seedHashes[n] = 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);
}

2
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());

1
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;

1
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.

12
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();
}

3
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<unsigned, unsigned> items() const { ReadGuard l(m_lock); return std::make_pair(m_ready.size(), m_unknown.size()); }

37
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();
ETH_WRITE_UNGUARDED(x_stateDB)
tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, db, 100);
x_stateDB.lock();
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,10 +522,8 @@ void Client::onChainChanged(ImportRoute const& _ir)
m_postMine = m_preMine;
changeds.insert(PendingChangedFilter);
x_stateDB.unlock_shared();
ETH_WRITE_UNGUARDED(x_stateDB)
onPostStateChanged();
x_stateDB.lock_shared();
}
}
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);
}
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)

4
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

6
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<Miner>(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<bool> m_isMining = {false};
mutable SharedMutex x_progress;
mutable MiningProgress m_progress;
std::chrono::steady_clock::time_point m_lastStart;

Loading…
Cancel
Save