Browse Source

Upgrade to latest ethhash API.

cl-refactor
Gav Wood 10 years ago
parent
commit
3efcc49bdf
  1. 78
      libethash/ethash.h
  2. 30
      libethash/internal.c
  3. 6
      libethash/internal.h
  4. 2
      libethash/io.c
  5. 2
      libethash/io_posix.c
  6. 2
      libethash/io_win32.c
  7. 25
      libethcore/Ethasher.cpp
  8. 27
      libethcore/Ethasher.h
  9. 4
      test/dagger.cpp

78
libethash/ethash.h

@ -24,19 +24,20 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include "compiler.h" #include "compiler.h"
#define REVISION 23 #define ETHASH_REVISION 23
#define DATASET_BYTES_INIT 1073741824U // 2**30 #define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30
#define DATASET_BYTES_GROWTH 8388608U // 2**23 #define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23
#define CACHE_BYTES_INIT 1073741824U // 2**24 #define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24
#define CACHE_BYTES_GROWTH 131072U // 2**17 #define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17
#define EPOCH_LENGTH 30000U #define ETHASH_EPOCH_LENGTH 30000U
#define MIX_BYTES 128 #define ETHASH_MIX_BYTES 128
#define HASH_BYTES 64 #define ETHASH_HASH_BYTES 64
#define DATASET_PARENTS 256 #define ETHASH_DATASET_PARENTS 256
#define CACHE_ROUNDS 3 #define ETHASH_CACHE_ROUNDS 3
#define ACCESSES 64 #define ETHASH_ACCESSES 64
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -61,34 +62,49 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc
params->cache_size = ethash_get_cachesize(block_number); params->cache_size = ethash_get_cachesize(block_number);
} }
typedef struct ethash_cache { /***********************************
void *mem; * OLD API *************************
} ethash_cache; ***********************************
******************** (deprecated) *
***********************************/
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number); void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
void ethash_mkcache(void *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_compute_full_data(void *mem, ethash_params const *params, void const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { /***********************************
ethash_cache c; * NEW API *************************
c.mem = cache; ***********************************/
ethash_mkcache(&c, params, seed);
} // TODO: compute params and seed in ethash_new_light; it should take only block_number
// TODO: store params in ethash_light_t/ethash_full_t to avoid having to repass into compute/new_full
typedef uint8_t const ethash_seedhash_t[32];
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { typedef void const* ethash_light_t;
ethash_cache c; static inline ethash_light_t ethash_new_light(ethash_params const* params, ethash_seedhash_t seed) {
c.mem = (void *) cache; void* ret = malloc(params->cache_size);
ethash_light(ret, &c, params, header_hash, nonce); ethash_mkcache(ret, params, seed);
return ret;
}
static inline void ethash_compute_light(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_light(ret, light, params, header_hash, nonce);
}
static inline void ethash_delete_light(ethash_light_t light) {
free((void*)light);
} }
typedef void const* ethash_full_t;
static inline ethash_full_t ethash_new_full(ethash_params const* params, ethash_light_t light) {
void* ret = malloc(params->full_size);
ethash_compute_full_data(ret, params, light);
return ret;
}
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_cache c; ethash_compute_full_data(full, params, cache);
c.mem = (void *) cache;
ethash_compute_full_data(full, params, &c);
} }
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_full(ret, full, params, header_hash, nonce); ethash_full(ret, full, params, header_hash, nonce);
} }

30
libethash/internal.c

@ -38,13 +38,13 @@
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(const uint32_t block_number) { uint64_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 2048); assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return dag_sizes[block_number / EPOCH_LENGTH]; return dag_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
uint64_t ethash_get_cachesize(const uint32_t block_number) { uint64_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 2048); assert(block_number / ETHASH_EPOCH_LENGTH < 2048);
return cache_sizes[block_number / EPOCH_LENGTH]; return cache_sizes[block_number / ETHASH_EPOCH_LENGTH];
} }
// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014)
@ -63,7 +63,7 @@ void static ethash_compute_cache_nodes(
SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64);
} }
for (unsigned j = 0; j != CACHE_ROUNDS; j++) { for (unsigned j = 0; j != ETHASH_CACHE_ROUNDS; j++) {
for (unsigned i = 0; i != num_nodes; i++) { for (unsigned i = 0; i != num_nodes; i++) {
uint32_t const idx = nodes[i].words[0] % num_nodes; uint32_t const idx = nodes[i].words[0] % num_nodes;
node data; node data;
@ -85,10 +85,10 @@ void static ethash_compute_cache_nodes(
} }
void ethash_mkcache( void ethash_mkcache(
ethash_cache *cache, void *cache,
ethash_params const *params, ethash_params const *params,
const uint8_t seed[32]) { const uint8_t seed[32]) {
node *nodes = (node *) cache->mem; node *nodes = (node *) cache;
ethash_compute_cache_nodes(nodes, params, seed); ethash_compute_cache_nodes(nodes, params, seed);
} }
@ -96,10 +96,10 @@ void ethash_calculate_dag_item(
node *const ret, node *const ret,
const unsigned node_index, const unsigned node_index,
const struct ethash_params *params, const struct ethash_params *params,
const struct ethash_cache *cache) { const void *cache) {
uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem; node const *cache_nodes = (node const *) cache;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node)); memcpy(ret, init, sizeof(node));
@ -114,7 +114,7 @@ void ethash_calculate_dag_item(
__m128i xmm3 = ret->xmm[3]; __m128i xmm3 = ret->xmm[3];
#endif #endif
for (unsigned i = 0; i != DATASET_PARENTS; ++i) { for (unsigned i = 0; i != ETHASH_DATASET_PARENTS; ++i) {
uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes; uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index]; node const *parent = &cache_nodes[parent_index];
@ -150,7 +150,7 @@ void ethash_calculate_dag_item(
void ethash_compute_full_data( void ethash_compute_full_data(
void *mem, void *mem,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache) { void const *cache) {
assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0);
assert((params->full_size % sizeof(node)) == 0); assert((params->full_size % sizeof(node)) == 0);
node *full_nodes = mem; node *full_nodes = mem;
@ -164,7 +164,7 @@ void ethash_compute_full_data(
static void ethash_hash( static void ethash_hash(
ethash_return_value *ret, ethash_return_value *ret,
node const *full_nodes, node const *full_nodes,
ethash_cache const *cache, void const *cache,
ethash_params const *params, ethash_params const *params,
const uint8_t header_hash[32], const uint8_t header_hash[32],
const uint64_t nonce) { const uint64_t nonce) {
@ -201,7 +201,7 @@ static void ethash_hash(
num_full_pages = (unsigned) (params->full_size / page_size); num_full_pages = (unsigned) (params->full_size / page_size);
for (unsigned i = 0; i != ACCESSES; ++i) { for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) {
uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages; uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n) { for (unsigned n = 0; n != MIX_NODES; ++n) {
@ -275,7 +275,7 @@ void ethash_quick_hash(
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) { void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) {
memset(seedhash, 0, 32); memset(seedhash, 0, 32);
const uint32_t epochs = block_number / EPOCH_LENGTH; const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i) for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, seedhash, 32); SHA3_256(seedhash, seedhash, 32);
} }
@ -295,6 +295,6 @@ void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params c
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
} }
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void ethash_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, NULL, cache, params, previous_hash, nonce); ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
} }

6
libethash/internal.h

@ -15,7 +15,7 @@ extern "C" {
// compile time settings // compile time settings
#define NODE_WORDS (64/4) #define NODE_WORDS (64/4)
#define MIX_WORDS (MIX_BYTES/4) #define MIX_WORDS (ETHASH_MIX_BYTES/4)
#define MIX_NODES (MIX_WORDS / NODE_WORDS) #define MIX_NODES (MIX_WORDS / NODE_WORDS)
#include <stdint.h> #include <stdint.h>
@ -34,7 +34,7 @@ void ethash_calculate_dag_item(
node *const ret, node *const ret,
const unsigned node_index, const unsigned node_index,
ethash_params const *params, ethash_params const *params,
ethash_cache const *cache void const *cache
); );
void ethash_quick_hash( void ethash_quick_hash(
@ -45,4 +45,4 @@ void ethash_quick_hash(
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

2
libethash/io.c

@ -71,7 +71,7 @@ bool ethash_io_write(char const *dirname,
goto fail_free; goto fail_free;
} }
ethash_io_serialize_info(REVISION, seedhash, info_buffer); ethash_io_serialize_info(ETHASH_REVISION, seedhash, info_buffer);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) { if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) {
goto fail_free; goto fail_free;
} }

2
libethash/io_posix.c

@ -56,7 +56,7 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seed
goto close; goto close;
} }
ethash_io_serialize_info(REVISION, seedhash, expect_buffer); ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file // we have different memo contents so delete the memo file
if (unlink(memofile) != 0) { if (unlink(memofile) != 0) {

2
libethash/io_win32.c

@ -53,7 +53,7 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_blockhash_t seed
goto close; goto close;
} }
ethash_io_serialize_info(REVISION, seedhash, expect_buffer); ethash_io_serialize_info(ETHASH_REVISION, seedhash, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file // we have different memo contents so delete the memo file
if (_unlink(memofile) != 0) { if (_unlink(memofile) != 0) {

25
libethcore/Ethasher.cpp

@ -41,7 +41,23 @@ using namespace eth;
Ethasher* dev::eth::Ethasher::s_this = nullptr; Ethasher* dev::eth::Ethasher::s_this = nullptr;
bytes const& Ethasher::cache(BlockInfo const& _header) Ethasher::~Ethasher()
{
while (!m_caches.empty())
killCache(m_caches.begin()->first);
}
void Ethasher::killCache(h256 const& _s)
{
RecursiveGuard l(x_this);
if (m_caches.count(_s))
{
ethash_delete_light(m_caches.at(_s));
m_caches.erase(_s);
}
}
void const* Ethasher::cache(BlockInfo const& _header)
{ {
RecursiveGuard l(x_this); RecursiveGuard l(x_this);
if (_header.number > c_ethashEpochLength * 2048) if (_header.number > c_ethashEpochLength * 2048)
@ -54,8 +70,7 @@ bytes const& Ethasher::cache(BlockInfo const& _header)
if (!m_caches.count(_header.seedHash())) if (!m_caches.count(_header.seedHash()))
{ {
ethash_params p = params((unsigned)_header.number); ethash_params p = params((unsigned)_header.number);
m_caches[_header.seedHash()].resize(p.cache_size); m_caches[_header.seedHash()] = ethash_new_light(&p, _header.seedHash().data());
ethash_prep_light(m_caches[_header.seedHash()].data(), &p, _header.seedHash().data());
} }
return m_caches[_header.seedHash()]; return m_caches[_header.seedHash()];
} }
@ -84,7 +99,7 @@ bytesConstRef Ethasher::full(BlockInfo const& _header)
ethash_params p = params((unsigned)_header.number); ethash_params p = params((unsigned)_header.number);
m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size); m_fulls[_header.seedHash()] = bytesRef(new byte[p.full_size], p.full_size);
auto c = cache(_header); auto c = cache(_header);
ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c.data()); ethash_prep_full(m_fulls[_header.seedHash()].data(), &p, c);
writeFile(memoFile, m_fulls[_header.seedHash()]); writeFile(memoFile, m_fulls[_header.seedHash()]);
writeFile(memoFile + ".info", info); writeFile(memoFile + ".info", info);
} }
@ -147,7 +162,7 @@ Ethasher::Result Ethasher::eval(BlockInfo const& _header, Nonce const& _nonce)
{ {
auto p = Ethasher::params(_header); auto p = Ethasher::params(_header);
ethash_return_value r; ethash_return_value r;
ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); ethash_compute_light(&r, Ethasher::get()->cache(_header), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce);
// cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer); // cdebug << "Ethasher::eval sha3(cache):" << sha3(Ethasher::get()->cache(_header)) << "hh:" << _header.headerHash(WithoutNonce) << "nonce:" << _nonce << " => " << h256(r.result, h256::ConstructFromPointer);
return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)};
} }

27
libethcore/Ethasher.h

@ -30,21 +30,8 @@
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcrypto/SHA3.h> #include <libdevcrypto/SHA3.h>
#include <libethash/ethash.h> // TODO: REMOVE once everything merged into this class and an opaque API can be provided. #include <libethash/ethash.h> // TODO: REMOVE once everything merged into this class and an opaque API can be provided.
static const unsigned c_ethashRevision = REVISION; static const unsigned c_ethashRevision = ETHASH_REVISION;
static const unsigned c_ethashEpochLength = EPOCH_LENGTH; static const unsigned c_ethashEpochLength = ETHASH_EPOCH_LENGTH;
#undef REVISION
#undef DATASET_BYTES_INIT
#undef DATASET_BYTES_GROWTH
#undef CACHE_BYTES_INIT
#undef CACHE_BYTES_GROWTH
#undef DAGSIZE_BYTES_INIT
#undef DAG_GROWTH
#undef EPOCH_LENGTH
#undef MIX_BYTES
#undef HASH_BYTES
#undef DATASET_PARENTS
#undef CACHE_ROUNDS
#undef ACCESSES
#include "Common.h" #include "Common.h"
#include "BlockInfo.h" #include "BlockInfo.h"
@ -57,10 +44,14 @@ class Ethasher
{ {
public: public:
Ethasher() {} Ethasher() {}
~Ethasher();
static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; }
bytes const& cache(BlockInfo const& _header); using LightType = void const*;
using FullType = void const*;
LightType cache(BlockInfo const& _header);
bytesConstRef full(BlockInfo const& _header); bytesConstRef full(BlockInfo const& _header);
static ethash_params params(BlockInfo const& _header); static ethash_params params(BlockInfo const& _header);
static ethash_params params(unsigned _n); static ethash_params params(unsigned _n);
@ -104,9 +95,11 @@ public:
}; };
private: private:
void killCache(h256 const& _s);
static Ethasher* s_this; static Ethasher* s_this;
RecursiveMutex x_this; RecursiveMutex x_this;
std::map<h256, bytes> m_caches; std::map<h256, LightType> m_caches;
std::map<h256, bytesRef> m_fulls; std::map<h256, bytesRef> m_fulls;
}; };

4
test/dagger.cpp

@ -63,8 +63,8 @@ BOOST_AUTO_TEST_CASE(basic_test)
unsigned cacheSize(o["cache_size"].get_int()); unsigned cacheSize(o["cache_size"].get_int());
h256 cacheHash(o["cache_hash"].get_str()); h256 cacheHash(o["cache_hash"].get_str());
BOOST_REQUIRE_EQUAL(Ethasher::get()->cache(header).size(), cacheSize); BOOST_REQUIRE_EQUAL(Ethasher::get()->params(header).cache_size, cacheSize);
BOOST_REQUIRE_EQUAL(sha3(Ethasher::get()->cache(header)), cacheHash); BOOST_REQUIRE_EQUAL(sha3(bytesConstRef((byte const*)Ethasher::get()->cache(header), cacheSize)), cacheHash);
#if TEST_FULL #if TEST_FULL
unsigned fullSize(o["full_size"].get_int()); unsigned fullSize(o["full_size"].get_int());

Loading…
Cancel
Save