Browse Source

New Proof-of-Work.

cl-refactor
Gav Wood 10 years ago
parent
commit
eaef000af3
  1. 5
      alethzero/MainWin.cpp
  2. 5
      libdevcore/CommonIO.cpp
  3. 6
      libdevcore/CommonIO.h
  4. 20
      libethcore/BlockInfo.cpp
  5. 6
      libethcore/BlockInfo.h
  6. 2
      libethcore/Common.cpp
  7. 2
      libethcore/Exceptions.h
  8. 98
      libethcore/ProofOfWork.cpp
  9. 9
      libethcore/ProofOfWork.h
  10. 2
      libethereum/State.cpp
  11. 22
      test/dagger.cpp

5
alethzero/MainWin.cpp

@ -1409,10 +1409,7 @@ void Main::on_blocks_currentItemChanged()
s << "<br/>Hash w/o nonce: <b>" << info.headerHash(WithoutNonce) << "</b>";
s << "<br/>Difficulty: <b>" << info.difficulty << "</b>";
if (info.number)
{
auto e = Ethasher::eval(info);
s << "<br/>Proof-of-Work: <b>" << e.value << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b> (mixhash: " << e.mixHash.abridged() << ")";
}
s << "<br/>Proof-of-Work: <b>" << ProofOfWork::eval(info) << " &lt;= " << (h256)u256((bigint(1) << 256) / info.difficulty) << "</b>";
else
s << "<br/>Proof-of-Work: <i>Phil has nothing to prove</i>";
s << "<br/>Parent: <b>" << info.parentHash << "</b>";

5
libdevcore/CommonIO.cpp

@ -115,3 +115,8 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data)
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}
void dev::writeFile(std::string const& _file, bytesConstRef _data)
{
ofstream(_file, ios::trunc).write((char const*)_data.data(), _data.size());
}

6
libdevcore/CommonIO.h

@ -43,15 +43,13 @@ namespace dev
/// Retrieve and returns the contents of the given file. If the file doesn't exist or isn't readable, returns an empty bytes.
bytes contents(std::string const& _file);
std::string contentsString(std::string const& _file);
/// Retrieve and returns the allocated contents of the given file. If the file doesn't exist or isn't readable, returns nullptr. Don't forget to delete [] when finished.
bytesRef contentsNew(std::string const& _file);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
void writeFile(std::string const& _file, bytesConstRef _data);
void writeFile(std::string const& _file, bytes const& _data);
/// Write the given binary data into the given file, replacing the file if it pre-exists.
inline void writeFile(std::string const& _file, bytes const& _data) { writeFile(_file, bytesConstRef(&_data)); }
inline void writeFile(std::string const& _file, std::string const& _data) { writeFile(_file, bytesConstRef(_data)); }
void writeFile(std::string const& _file, bytesConstRef _data);
/// Nicely renders the given bytes to a string, optionally as HTML.
/// @a _bytes: bytes array to be rendered as string. @a _width of a bytes line.

20
libethcore/BlockInfo.cpp

@ -31,6 +31,8 @@ using namespace std;
using namespace dev;
using namespace dev::eth;
u256 dev::eth::c_genesisDifficulty = (u256)1 << 11;
BlockInfo::BlockInfo(): timestamp(Invalid256)
{
}
@ -56,7 +58,7 @@ void BlockInfo::setEmpty()
timestamp = 0;
extraData.clear();
seedHash = h256();
mixHash = h256();
mixBytes = h256();
nonce = Nonce();
hash = headerHash(WithNonce);
}
@ -81,7 +83,7 @@ void BlockInfo::streamRLP(RLPStream& _s, IncludeNonce _n) const
<< parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot << receiptsRoot << logBloom
<< difficulty << number << gasLimit << gasUsed << timestamp << extraData << seedHash;
if (_n == WithNonce)
_s << mixHash << nonce;
_s << mixBytes << nonce;
}
h256 BlockInfo::headerHash(bytesConstRef _block)
@ -109,9 +111,9 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce)
gasUsed = _header[field = 10].toInt<u256>();
timestamp = _header[field = 11].toInt<u256>();
extraData = _header[field = 12].toBytes();
seedHash = _header[field = 13].toHash<h256>(RLP::VeryStrict);
mixHash = _header[field = 14].toHash<h256>(RLP::VeryStrict);
nonce = _header[field = 15].toHash<Nonce>(RLP::VeryStrict);
seedHash = _header[field = 13].toHash<h256>();
mixBytes = _header[field = 14].toHash<h256>();
nonce = _header[field = 15].toHash<Nonce>();
}
catch (Exception const& _e)
@ -185,12 +187,7 @@ void BlockInfo::populateFromParent(BlockInfo const& _parent)
gasLimit = calculateGasLimit(_parent);
gasUsed = 0;
difficulty = calculateDifficulty(_parent);
seedHash = calculateSeedHash(_parent);
}
h256 BlockInfo::calculateSeedHash(BlockInfo const& _parent) const
{
return number % c_epochDuration == 0 ? sha3(_parent.seedHash.asBytes()) : _parent.seedHash;
seedHash = number % 30 == 0 ? sha3(_parent.seedHash.asBytes() /*+ _parent.hash.asBytes()*/) : _parent.seedHash;
}
u256 BlockInfo::calculateGasLimit(BlockInfo const& _parent) const
@ -224,7 +221,6 @@ void BlockInfo::verifyParent(BlockInfo const& _parent) const
if (diff(gasLimit, _parent.gasLimit) <= _parent.gasLimit / 1024)
BOOST_THROW_EXCEPTION(InvalidGasLimit(gasLimit, calculateGasLimit(_parent), diff(gasLimit, _parent.gasLimit), _parent.gasLimit / 1024));
// Check timestamp is after previous timestamp.
if (parentHash)
{

6
libethcore/BlockInfo.h

@ -74,7 +74,7 @@ public:
u256 gasUsed;
u256 timestamp;
bytes extraData;
h256 mixHash;
h256 mixBytes;
h256 seedHash;
Nonce nonce;
@ -105,7 +105,7 @@ public:
gasUsed == _cmp.gasUsed &&
timestamp == _cmp.timestamp &&
extraData == _cmp.extraData &&
mixHash == _cmp.mixHash &&
mixBytes == _cmp.mixBytes &&
seedHash == _cmp.seedHash &&
nonce == _cmp.nonce;
}
@ -133,7 +133,7 @@ inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi)
{
_out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " <<
_bi.receiptsRoot << " " << _bi.logBloom << " " << _bi.difficulty << " " << _bi.number << " " << _bi.gasLimit << " " <<
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixHash << " " << _bi.seedHash << " " << _bi.nonce;
_bi.gasUsed << " " << _bi.timestamp << " " << _bi.mixBytes << " " << _bi.seedHash << " " << _bi.nonce;
return _out;
}

2
libethcore/Common.cpp

@ -32,7 +32,7 @@ namespace dev
namespace eth
{
const unsigned c_protocolVersion = 55;
const unsigned c_protocolVersion = 56;
const unsigned c_databaseVersion = 6 +
#if ETH_FATDB
1000

2
libethcore/Exceptions.h

@ -22,7 +22,7 @@
#pragma once
#include <libdevcore/Exceptions.h>
#include "Common.h"
#include "CommonEth.h"
namespace dev
{

98
libethcore/ProofOfWork.cpp

@ -30,8 +30,8 @@
#include <libdevcrypto/CryptoPP.h>
#include <libdevcrypto/FileSystem.h>
#include <libdevcore/Common.h>
#include <libethash/ethash.h>
#include "BlockInfo.h"
#include "Ethasher.h"
#include "ProofOfWork.h"
using namespace std;
using namespace std::chrono;
@ -41,14 +41,100 @@ namespace dev
namespace eth
{
class Ethasher
{
public:
Ethasher() {}
static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; }
bytes const& cache(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (!m_caches.count(_header.seedHash))
{
try {
boost::filesystem::create_directories(getDataDir() + "/ethashcache");
} catch (...) {}
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".cache";
m_caches[_header.seedHash] = contents(memoFile);
if (m_caches[_header.seedHash].empty())
{
ethash_params p = params((unsigned)_header.number);
m_caches[_header.seedHash].resize(p.cache_size);
ethash_prep_light(m_caches[_header.seedHash].data(), &p, _header.seedHash.data());
writeFile(memoFile, m_caches[_header.seedHash]);
}
}
return m_caches[_header.seedHash];
}
byte const* full(BlockInfo const& _header)
{
RecursiveGuard l(x_this);
if (!m_fulls.count(_header.seedHash))
{
if (!m_fulls.empty())
{
delete [] m_fulls.begin()->second.data();
m_fulls.erase(m_fulls.begin());
}
std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".full";
m_fulls[_header.seedHash] = contentsNew(memoFile);
if (!m_fulls[_header.seedHash])
{
ethash_params p = params((unsigned)_header.number);
m_fulls[_header.seedHash] = bytesRef(new byte[p.full_size], p.full_size);
auto c = cache(_header);
ethash_prep_full(m_fulls[_header.seedHash].data(), &p, c.data());
writeFile(memoFile, m_fulls[_header.seedHash]);
}
}
return m_fulls[_header.seedHash].data();
}
static ethash_params params(BlockInfo const& _header)
{
return params((unsigned)_header.number);
}
static ethash_params params(unsigned _n)
{
ethash_params p;
p.cache_size = ethash_get_cachesize(_n);
p.full_size = ethash_get_datasize(_n);
return p;
}
private:
static Ethasher* s_this;
RecursiveMutex x_this;
std::map<h256, bytes> m_caches;
std::map<h256, bytesRef> m_fulls;
};
Ethasher* Ethasher::s_this = nullptr;
bool Ethash::verify(BlockInfo const& _header)
{
return Ethasher::verify(_header);
bigint boundary = (bigint(1) << 256) / _header.difficulty;
u256 e(eval(_header, _header.nonce));
return e <= boundary;
}
h256 Ethash::eval(BlockInfo const& _header, Nonce const& _nonce)
{
auto p = Ethasher::params(_header);
ethash_return_value r;
ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce);
return h256(r.result, h256::ConstructFromPointer);
}
std::pair<MineInfo, Ethash::Proof> Ethash::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo)
{
Ethasher::Miner m(_header);
auto h = _header.headerHash(WithoutNonce);
auto p = Ethasher::params(_header);
auto d = Ethasher::get()->full(_header);
std::pair<MineInfo, Proof> ret;
static std::mt19937_64 s_eng((time(0) + *reinterpret_cast<unsigned*>(m_last.data())));
@ -66,15 +152,17 @@ std::pair<MineInfo, Ethash::Proof> Ethash::mine(BlockInfo const& _header, unsign
std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100));
double best = 1e99; // high enough to be effectively infinity :)
Proof result;
ethash_return_value ethashReturn;
unsigned hashCount = 0;
for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++)
{
u256 val(m.mine(tryNonce));
ethash_compute_full(&ethashReturn, d, &p, h.data(), tryNonce);
u256 val(h256(ethashReturn.result, h256::ConstructFromPointer));
best = std::min<double>(best, log2((double)val));
if (val <= boundary)
{
ret.first.completed = true;
result.mixHash = m.lastMixHash();
result.mixHash = *reinterpret_cast<h256 const*>(ethashReturn.mix_hash);
result.nonce = u64(tryNonce);
break;
}

9
libethcore/ProofOfWork.h

@ -27,7 +27,7 @@
#include <thread>
#include <cstdint>
#include <libdevcrypto/SHA3.h>
#include "Common.h"
#include "CommonEth.h"
#include "BlockInfo.h"
#define FAKE_DAGGER 1
@ -49,15 +49,18 @@ struct MineInfo
class Ethash
{
public:
// bit-compatible with ethash_return_value
struct Proof
{
Nonce nonce;
h256 mixHash;
};
static h256 eval(BlockInfo const& _header) { return eval(_header, _header.nonce); }
static h256 eval(BlockInfo const& _header, Nonce const& _nonce);
static bool verify(BlockInfo const& _header);
std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; }
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixBytes = _r.mixHash; }
protected:
Nonce m_last;
@ -70,7 +73,9 @@ public:
using Proof = Nonce;
static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; }
inline std::pair<MineInfo, Proof> mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false);
static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; }
protected:

2
libethereum/State.cpp

@ -547,7 +547,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles());
set<h256> nonces = { m_currentBlock.nonce };
set<Nonce> nonces = { m_currentBlock.nonce };
Addresses rewarded;
set<h256> knownUncles = _bc.allUnclesFrom(m_currentBlock.parentHash);

22
test/dagger.cpp

@ -41,16 +41,16 @@ BOOST_AUTO_TEST_SUITE(DashimotoTests)
BOOST_AUTO_TEST_CASE(basic_test)
{
string testPath = test::getTestPath();
testPath += "/PoWTests";
cnote << "Testing Secure Trie...";
js::mValue v;
string s = asString(contents(testPath + "/ethash_tests.json"));
BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?");
js::read_string(s, v);
for (auto& i: v.get_obj())
#if 0
cnote << "Testing ProofOfWork...";
// Test dagger
{
auto s = steady_clock::now();
cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0);
cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl;
cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1);
cout << " " << dec << duration_cast<milliseconds>(steady_clock::now() - s).count() << " ms" << endl;
}
{
cnote << i.first;
js::mObject& o = i.second.get_obj();
@ -78,6 +78,8 @@ BOOST_AUTO_TEST_CASE(basic_test)
BOOST_REQUIRE_EQUAL(r.value, result);
BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash);
}
#endif
return 0;
}
BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save