const& _h)
{
- return (*this |= _h.template bloom());
+ return (*this |= _h.template bloomPart
());
}
template inline bool containsBloom(FixedHash const& _h)
{
- return contains(_h.template bloom());
+ return contains(_h.template bloomPart
());
}
- template inline FixedHash bloom() const
+ template inline FixedHash bloomPart() const
{
+ static_assert((M & (M - 1)) == 0, "M must be power-of-two");
static const unsigned c_bloomBits = M * 8;
unsigned mask = c_bloomBits - 1;
unsigned bloomBytes = (dev::toLog2(c_bloomBits) + 7) / 8;
diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp
index 846664cfd..330893c76 100644
--- a/libdevcore/RLP.cpp
+++ b/libdevcore/RLP.cpp
@@ -202,9 +202,7 @@ unsigned RLP::items() const
RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount)
{
- unsigned os = m_out.size();
- m_out.resize(os + _s.size());
- memcpy(m_out.data() + os, _s.data(), _s.size());
+ m_out.insert(m_out.end(), _s.begin(), _s.end());
noteAppended(_itemCount);
return *this;
}
diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h
index 6e46807ab..6ae9c165b 100644
--- a/libdevcore/RLP.h
+++ b/libdevcore/RLP.h
@@ -292,7 +292,7 @@ public:
RLPs toList() const;
/// @returns the data payload. Valid for all types.
- bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); }
+ bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); }
/// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h
index f9d7bff5f..f35cf893c 100644
--- a/libdevcore/TrieDB.h
+++ b/libdevcore/TrieDB.h
@@ -21,19 +21,14 @@
#pragma once
-#pragma warning(push)
-#pragma warning(disable: 4100 4267)
-#include
-#pragma warning(pop)
-
#include
-#include
-#include
-#include
-#include
+#include "db.h"
+#include "Common.h"
+#include "Log.h"
+#include "Exceptions.h"
+#include "SHA3.h"
#include "MemoryDB.h"
#include "TrieCommon.h"
-namespace ldb = leveldb;
namespace dev
{
diff --git a/libdevcore/db.h b/libdevcore/db.h
new file mode 100644
index 000000000..4d000af78
--- /dev/null
+++ b/libdevcore/db.h
@@ -0,0 +1,36 @@
+/*
+ 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 .
+*/
+/** @file DB.h
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#pragma once
+
+#pragma warning(push)
+#pragma warning(disable: 4100 4267)
+#if ETH_ROCKSDB || !ETH_TRUE
+#include
+#include
+namespace ldb = rocksdb;
+#else
+#include
+#include
+namespace ldb = leveldb;
+#endif
+#pragma warning(pop)
+#define DEV_LDB 1
diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h
index b04d449b3..b05342f71 100644
--- a/libdevcore/vector_ref.h
+++ b/libdevcore/vector_ref.h
@@ -9,6 +9,9 @@
namespace dev
{
+/**
+ * A modifiable reference to an existing object or vector in memory.
+ */
template
class vector_ref
{
@@ -17,34 +20,50 @@ public:
using element_type = _T;
using mutable_value_type = typename std::conditional::value, typename std::remove_const<_T>::type, _T>::type;
+ static_assert(std::is_pod::value, "vector_ref can only be used with PODs due to its low-level treatment of data.");
+
vector_ref(): m_data(nullptr), m_count(0) {}
+ /// Creates a new vector_ref to point to @a _count elements starting at @a _data.
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
+ /// Creates a new vector_ref pointing to the data part of a string (given as pointer).
vector_ref(typename std::conditional::value, std::string const*, std::string*>::type _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {}
+ /// Creates a new vector_ref pointing to the data part of a vector (given as pointer).
vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {}
- vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data((_T*)_data.data()), m_count(_data.size() / sizeof(_T)) {}
-#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
- vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {}
+ /// Creates a new vector_ref pointing to the data part of a string (given as reference).
+ vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {}
+#if DEV_LDB
+ vector_ref(ldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {}
#endif
explicit operator bool() const { return m_data && m_count; }
- bool contentsEqual(std::vector const& _c) const { return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count); }
+ bool contentsEqual(std::vector const& _c) const { if (!m_data || m_count == 0) return _c.empty(); else return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T)); }
std::vector toVector() const { return std::vector(m_data, m_data + m_count); }
std::vector toBytes() const { return std::vector(reinterpret_cast(m_data), reinterpret_cast(m_data) + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
+
template explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); }
operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); }
_T* data() const { return m_data; }
+ /// @returns the number of elements referenced (not necessarily number of bytes).
size_t count() const { return m_count; }
+ /// @returns the number of elements referenced (not necessarily number of bytes).
size_t size() const { return m_count; }
bool empty() const { return !m_count; }
- vector_ref<_T> next() const { return vector_ref<_T>(m_data + m_count, m_count); }
+ /// @returns a new vector_ref pointing at the next chunk of @a size() elements.
+ vector_ref<_T> next() const { if (!m_data) return *this; else return vector_ref<_T>(m_data + m_count, m_count); }
+ /// @returns a new vector_ref which is a shifted and shortened view of the original data.
+ /// If this goes out of bounds in any way, returns an empty vector_ref.
+ /// If @a _count is ~size_t(0), extends the view to the end of the data.
vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
+ /// @returns a new vector_ref which is a shifted view of the original data (not going beyond it).
vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); }
void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; }
void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); }
template bool overlapsWith(vector_ref _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; }
+ /// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a _t.
void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
+ /// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t.
void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
_T* begin() { return m_data; }
@@ -58,8 +77,8 @@ public:
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
-#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_
- operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); }
+#if DEV_LDB
+ operator ldb::Slice() const { return ldb::Slice((char const*)m_data, m_count * sizeof(_T)); }
#endif
void reset() { m_data = nullptr; m_count = 0; }
diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h
index 32d1880dc..6aaed6fad 100644
--- a/libdevcrypto/AES.h
+++ b/libdevcrypto/AES.h
@@ -75,6 +75,8 @@ public:
/// Adjust mac interval. Next mac will be xored with value.
void adjustInterval(unsigned _interval) { m_macInterval = _interval; }
+
+ unsigned getMacInterval() { return m_macInterval;}
private:
AuthenticatedStream(AuthenticatedStream const&) = delete;
diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt
index 7df1149b0..d30aa7bc1 100644
--- a/libdevcrypto/CMakeLists.txt
+++ b/libdevcrypto/CMakeLists.txt
@@ -12,7 +12,7 @@ aux_source_directory(. SRC_LIST)
include_directories(BEFORE ..)
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
-include_directories(${LEVELDB_INCLUDE_DIRS})
+include_directories(${DB_INCLUDE_DIRS})
set(EXECUTABLE devcrypto)
@@ -20,7 +20,7 @@ file(GLOB HEADERS "*.h")
add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES})
-target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES})
+target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES})
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES})
target_link_libraries(${EXECUTABLE} scrypt)
target_link_libraries(${EXECUTABLE} devcore)
diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp
index 4ebd6a04b..af61a1dd5 100644
--- a/libdevcrypto/Common.cpp
+++ b/libdevcrypto/Common.cpp
@@ -31,6 +31,7 @@
#include
#include "AES.h"
#include "CryptoPP.h"
+#include "Exceptions.h"
using namespace std;
using namespace dev;
using namespace dev::crypto;
@@ -178,15 +179,35 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
{
bytes ret(_dkLen);
- PKCS5_PBKDF2_HMAC pbkdf;
- pbkdf.DeriveKey(ret.data(), ret.size(), 0, (byte*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _iterations);
+ if (PKCS5_PBKDF2_HMAC().DeriveKey(
+ ret.data(),
+ ret.size(),
+ 0,
+ reinterpret_cast(_pass.data()),
+ _pass.size(),
+ _salt.data(),
+ _salt.size(),
+ _iterations
+ ) != _iterations)
+ BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed."));
return ret;
}
bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
{
bytes ret(_dkLen);
- libscrypt_scrypt((uint8_t const*)_pass.data(), _pass.size(), _salt.data(), _salt.size(), _n, _r, _p, ret.data(), ret.size());
+ if (libscrypt_scrypt(
+ reinterpret_cast(_pass.data()),
+ _pass.size(),
+ _salt.data(),
+ _salt.size(),
+ _n,
+ _r,
+ _p,
+ ret.data(),
+ ret.size()
+ ) != 0)
+ BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed."));
return ret;
}
@@ -233,42 +254,84 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash)
return s;
}
-h256 Nonce::get(bool _commit)
+mutex Nonce::s_x;
+static string s_seedFile;
+
+h256 Nonce::get()
{
// todo: atomic efface bit, periodic save, kdf, rr, rng
// todo: encrypt
- static h256 s_seed;
- static string s_seedFile(getDataDir() + "/seed");
- static mutex s_x;
- Guard l(s_x);
- if (!s_seed)
+ Guard l(Nonce::s_x);
+ return Nonce::singleton().next();
+}
+
+void Nonce::reset()
+{
+ Guard l(Nonce::s_x);
+ Nonce::singleton().resetInternal();
+}
+
+void Nonce::setSeedFilePath(string const& _filePath)
+{
+ s_seedFile = _filePath;
+}
+
+Nonce::~Nonce()
+{
+ Guard l(Nonce::s_x);
+ if (m_value)
+ // this might throw
+ resetInternal();
+}
+
+Nonce& Nonce::singleton()
+{
+ static Nonce s;
+ return s;
+}
+
+void Nonce::initialiseIfNeeded()
+{
+ if (m_value)
+ return;
+
+ bytes b = contents(seedFile());
+ if (b.size() == 32)
+ memcpy(m_value.data(), b.data(), 32);
+ else
{
- static Nonce s_nonce;
- bytes b = contents(s_seedFile);
- if (b.size() == 32)
- memcpy(s_seed.data(), b.data(), 32);
- else
- {
- // todo: replace w/entropy from user and system
- std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
- std::uniform_int_distribution d(0, 255);
- for (unsigned i = 0; i < 32; ++i)
- s_seed[i] = (byte)d(s_eng);
- }
- if (!s_seed)
- BOOST_THROW_EXCEPTION(InvalidState());
-
- // prevent seed reuse if process terminates abnormally
- writeFile(s_seedFile, bytes());
+ // todo: replace w/entropy from user and system
+ std::mt19937_64 s_eng(time(0) + chrono::high_resolution_clock::now().time_since_epoch().count());
+ std::uniform_int_distribution d(0, 255);
+ for (unsigned i = 0; i < 32; ++i)
+ m_value[i] = byte(d(s_eng));
}
- h256 prev(s_seed);
- sha3(prev.ref(), s_seed.ref());
- if (_commit)
- writeFile(s_seedFile, s_seed.asBytes());
- return std::move(s_seed);
+ if (!m_value)
+ BOOST_THROW_EXCEPTION(InvalidState());
+
+ // prevent seed reuse if process terminates abnormally
+ // this might throw
+ writeFile(seedFile(), bytes());
}
-Nonce::~Nonce()
+h256 Nonce::next()
+{
+ initialiseIfNeeded();
+ m_value = sha3(m_value);
+ return m_value;
+}
+
+void Nonce::resetInternal()
+{
+ // this might throw
+ next();
+ writeFile(seedFile(), m_value.asBytes());
+ m_value = h256();
+}
+
+string const& Nonce::seedFile()
{
- Nonce::get(true);
+ if (s_seedFile.empty())
+ s_seedFile = getDataDir() + "/seed";
+ return s_seedFile;
}
diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h
index 7bb51e563..b3d2649b8 100644
--- a/libdevcrypto/Common.h
+++ b/libdevcrypto/Common.h
@@ -24,6 +24,7 @@
#pragma once
+#include
#include
#include
#include
@@ -180,14 +181,36 @@ struct InvalidState: public dev::Exception {};
h256 kdf(Secret const& _priv, h256 const& _hash);
/**
- * @brief Generator for nonce material
+ * @brief Generator for nonce material.
*/
struct Nonce
{
- static h256 get(bool _commit = false);
+ /// Returns the next nonce (might be read from a file).
+ static h256 get();
+ /// Stores the current nonce in a file and resets Nonce to the uninitialised state.
+ static void reset();
+ /// Sets the location of the seed file to a non-default place. Used for testing.
+ static void setSeedFilePath(std::string const& _filePath);
+
private:
Nonce() {}
~Nonce();
+ /// @returns the singleton instance.
+ static Nonce& singleton();
+ /// Reads the last seed from the seed file.
+ void initialiseIfNeeded();
+ /// @returns the next nonce.
+ h256 next();
+ /// Stores the current seed in the seed file.
+ void resetInternal();
+ /// @returns the path of the seed file.
+ static std::string const& seedFile();
+
+ /// Mutex for the singleton object.
+ /// @note Every access to any private function has to be guarded by this mutex.
+ static std::mutex s_x;
+
+ h256 m_value;
};
}
diff --git a/libdevcrypto/Exceptions.h b/libdevcrypto/Exceptions.h
new file mode 100644
index 000000000..858374bda
--- /dev/null
+++ b/libdevcrypto/Exceptions.h
@@ -0,0 +1,35 @@
+/*
+ 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 .
+*/
+/** @file Exceptions.h
+ * @author Christian
+ * @date 2016
+ */
+
+#pragma once
+
+#include
+
+namespace dev
+{
+namespace crypto
+{
+
+/// Rare malfunction of cryptographic functions.
+DEV_SIMPLE_EXCEPTION(CryptoException);
+
+}
+}
diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp
index a6aa684f2..730d71b4d 100644
--- a/libdevcrypto/OverlayDB.cpp
+++ b/libdevcrypto/OverlayDB.cpp
@@ -20,8 +20,7 @@
*/
#include
-#include
-#include
+#include
#include
#include "OverlayDB.h"
using namespace std;
diff --git a/libdevcrypto/OverlayDB.h b/libdevcrypto/OverlayDB.h
index b37d2c11b..83618d8a3 100644
--- a/libdevcrypto/OverlayDB.h
+++ b/libdevcrypto/OverlayDB.h
@@ -21,16 +21,11 @@
#pragma once
-#pragma warning(push)
-#pragma warning(disable: 4100 4267)
-#include
-#pragma warning(pop)
-
#include
+#include
#include
#include
#include
-namespace ldb = leveldb;
namespace dev
{
diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp
index b9d4ccfc6..a7a16a1b8 100644
--- a/libdevcrypto/SecretStore.cpp
+++ b/libdevcrypto/SecretStore.cpp
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
using namespace std;
using namespace dev;
namespace js = json_spirit;
@@ -36,7 +37,8 @@ namespace fs = boost::filesystem;
static const int c_keyFileVersion = 3;
-static js::mValue upgraded(std::string const& _s)
+/// Upgrade the json-format to the current version.
+static js::mValue upgraded(string const& _s)
{
js::mValue v;
js::read_string(_s, v);
@@ -84,35 +86,34 @@ static js::mValue upgraded(std::string const& _s)
return js::mValue();
}
-SecretStore::SecretStore(std::string const& _path): m_path(_path)
+SecretStore::SecretStore(string const& _path): m_path(_path)
{
load();
}
-SecretStore::~SecretStore()
+bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const
{
-}
-
-bytes SecretStore::secret(h128 const& _uuid, function const& _pass, bool _useCache) const
-{
- (void)_pass;
auto rit = m_cached.find(_uuid);
if (_useCache && rit != m_cached.end())
return rit->second;
auto it = m_keys.find(_uuid);
- if (it == m_keys.end())
- return bytes();
- bytes key = decrypt(it->second.first, _pass());
- if (!key.empty())
- m_cached[_uuid] = key;
+ bytes key;
+ if (it != m_keys.end())
+ {
+ key = decrypt(it->second.encryptedKey, _pass());
+ if (!key.empty())
+ m_cached[_uuid] = key;
+ }
return key;
}
-h128 SecretStore::importSecret(bytes const& _s, std::string const& _pass)
+h128 SecretStore::importSecret(bytes const& _s, string const& _pass)
{
- h128 r = h128::random();
+ h128 r;
+ EncryptedKey key{encrypt(_s, _pass), string()};
+ r = h128::random();
m_cached[r] = _s;
- m_keys[r] = make_pair(encrypt(_s, _pass), std::string());
+ m_keys[r] = move(key);
save();
return r;
}
@@ -122,7 +123,7 @@ void SecretStore::kill(h128 const& _uuid)
m_cached.erase(_uuid);
if (m_keys.count(_uuid))
{
- boost::filesystem::remove(m_keys[_uuid].second);
+ fs::remove(m_keys[_uuid].filename);
m_keys.erase(_uuid);
}
}
@@ -132,50 +133,50 @@ void SecretStore::clearCache() const
m_cached.clear();
}
-void SecretStore::save(std::string const& _keysPath)
+void SecretStore::save(string const& _keysPath)
{
fs::path p(_keysPath);
- boost::filesystem::create_directories(p);
+ fs::create_directories(p);
for (auto& k: m_keys)
{
- std::string uuid = toUUID(k.first);
- std::string filename = (p / uuid).string() + ".json";
+ string uuid = toUUID(k.first);
+ string filename = (p / uuid).string() + ".json";
js::mObject v;
js::mValue crypto;
- js::read_string(k.second.first, crypto);
+ js::read_string(k.second.encryptedKey, crypto);
v["crypto"] = crypto;
v["id"] = uuid;
v["version"] = c_keyFileVersion;
writeFile(filename, js::write_string(js::mValue(v), true));
- if (!k.second.second.empty() && k.second.second != filename)
- boost::filesystem::remove(k.second.second);
- k.second.second = filename;
+ swap(k.second.filename, filename);
+ if (!filename.empty() && !fs::equivalent(filename, k.second.filename))
+ fs::remove(filename);
}
}
-void SecretStore::load(std::string const& _keysPath)
+void SecretStore::load(string const& _keysPath)
{
fs::path p(_keysPath);
- boost::filesystem::create_directories(p);
+ fs::create_directories(p);
for (fs::directory_iterator it(p); it != fs::directory_iterator(); ++it)
- if (is_regular_file(it->path()))
+ if (fs::is_regular_file(it->path()))
readKey(it->path().string(), true);
}
-h128 SecretStore::readKey(std::string const& _file, bool _deleteFile)
+h128 SecretStore::readKey(string const& _file, bool _takeFileOwnership)
{
cnote << "Reading" << _file;
- return readKeyContent(contentsString(_file), _deleteFile ? _file : string());
+ return readKeyContent(contentsString(_file), _takeFileOwnership ? _file : string());
}
-h128 SecretStore::readKeyContent(std::string const& _content, std::string const& _file)
+h128 SecretStore::readKeyContent(string const& _content, string const& _file)
{
js::mValue u = upgraded(_content);
if (u.type() == js::obj_type)
{
js::mObject& o = u.get_obj();
auto uuid = fromUUID(o["id"].get_str());
- m_keys[uuid] = make_pair(js::write_string(o["crypto"], false), _file);
+ m_keys[uuid] = EncryptedKey{js::write_string(o["crypto"], false), _file};
return uuid;
}
else
@@ -183,62 +184,63 @@ h128 SecretStore::readKeyContent(std::string const& _content, std::string const&
return h128();
}
-bool SecretStore::recode(h128 const& _uuid, string const& _newPass, std::function const& _pass, KDF _kdf)
+bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function const& _pass, KDF _kdf)
{
-// cdebug << "recode:" << toUUID(_uuid);
bytes s = secret(_uuid, _pass, true);
if (s.empty())
return false;
- m_keys[_uuid].first = encrypt(s, _newPass, _kdf);
+ m_cached.erase(_uuid);
+ m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf);
save();
return true;
}
-std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF _kdf)
+static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
{
- js::mObject ret;
-
- // KDF info
unsigned dklen = 32;
+ unsigned iterations = 1 << 18;
bytes salt = h256::random().asBytes();
- bytes derivedKey;
if (_kdf == KDF::Scrypt)
{
- unsigned iterations = 262144;
unsigned p = 1;
unsigned r = 8;
- ret["kdf"] = "scrypt";
+ o_ret["kdf"] = "scrypt";
{
js::mObject params;
- params["n"] = (int64_t)iterations;
- params["r"] = (int)r;
- params["p"] = (int)p;
- params["dklen"] = (int)dklen;
+ params["n"] = int64_t(iterations);
+ params["r"] = int(r);
+ params["p"] = int(p);
+ params["dklen"] = int(dklen);
params["salt"] = toHex(salt);
- ret["kdfparams"] = params;
+ o_ret["kdfparams"] = params;
}
- derivedKey = scrypt(_pass, salt, iterations, r, p, dklen);
+ return scrypt(_pass, salt, iterations, r, p, dklen);
}
else
{
- unsigned iterations = 262144;
- ret["kdf"] = "pbkdf2";
+ o_ret["kdf"] = "pbkdf2";
{
js::mObject params;
params["prf"] = "hmac-sha256";
- params["c"] = (int)iterations;
+ params["c"] = int(iterations);
params["salt"] = toHex(salt);
- params["dklen"] = (int)dklen;
- ret["kdfparams"] = params;
+ params["dklen"] = int(dklen);
+ o_ret["kdfparams"] = params;
}
- derivedKey = pbkdf2(_pass, salt, iterations, dklen);
+ return pbkdf2(_pass, salt, iterations, dklen);
}
-// cdebug << "derivedKey" << toHex(derivedKey);
+}
+
+string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf)
+{
+ js::mObject ret;
+
+ bytes derivedKey = deriveNewKey(_pass, _kdf, ret);
+ if (derivedKey.empty())
+ BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed."));
- // cipher info
ret["cipher"] = "aes-128-ctr";
h128 key(derivedKey, h128::AlignLeft);
-// cdebug << "cipherKey" << key.hex();
h128 iv = h128::random();
{
js::mObject params;
@@ -248,18 +250,18 @@ std::string SecretStore::encrypt(bytes const& _v, std::string const& _pass, KDF
// cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v);
+ if (cipherText.empty())
+ BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed."));
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
-// cdebug << "macBody" << toHex(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
-// cdebug << "mac" << mac.hex();
ret["mac"] = toHex(mac.ref());
- return js::write_string((js::mValue)ret, true);
+ return js::write_string(js::mValue(ret), true);
}
-bytes SecretStore::decrypt(std::string const& _v, std::string const& _pass)
+bytes SecretStore::decrypt(string const& _v, string const& _pass)
{
js::mObject o;
{
diff --git a/libdevcrypto/SecretStore.h b/libdevcrypto/SecretStore.h
index 4474212b1..029630b4e 100644
--- a/libdevcrypto/SecretStore.h
+++ b/libdevcrypto/SecretStore.h
@@ -35,41 +35,81 @@ enum class KDF {
Scrypt,
};
+/**
+ * Manages encrypted keys stored in a certain directory on disk. The keys are read into memory
+ * and changes to the keys are automatically synced to the directory.
+ * Each file stores exactly one key in a specific JSON format whose file name is derived from the
+ * UUID of the key.
+ * @note that most of the functions here affect the filesystem and throw exceptions on failure,
+ * and they also throw exceptions upon rare malfunction in the cryptographic functions.
+ */
class SecretStore
{
public:
+ /// Construct a new SecretStore and read all keys in the given directory.
SecretStore(std::string const& _path = defaultPath());
- ~SecretStore();
+ /// @returns the secret key stored by the given @a _uuid.
+ /// @param _pass function that returns the password for the key.
+ /// @param _useCache if true, allow previously decrypted keys to be returned directly.
bytes secret(h128 const& _uuid, std::function const& _pass, bool _useCache = true) const;
+ /// Imports the (encrypted) key stored in the file @a _file and copies it to the managed directory.
h128 importKey(std::string const& _file) { auto ret = readKey(_file, false); if (ret) save(); return ret; }
+ /// Imports the (encrypted) key contained in the json formatted @a _content and stores it in
+ /// the managed directory.
h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; }
+ /// Imports the decrypted key given by @a _s and stores it, encrypted with
+ /// (a key derived from) the password @a _pass.
h128 importSecret(bytes const& _s, std::string const& _pass);
+ /// Decrypts and re-encrypts the key identified by @a _uuid.
bool recode(h128 const& _uuid, std::string const& _newPass, std::function const& _pass, KDF _kdf = KDF::Scrypt);
+ /// Removes the key specified by @a _uuid from both memory and disk.
void kill(h128 const& _uuid);
+ /// Returns the uuids of all stored keys.
std::vector keys() const { return keysOf(m_keys); }
- // Clear any cached keys.
+ /// Clears all cached decrypted keys. The passwords have to be supplied in order to retrieve
+ /// secrets again after calling this function.
void clearCache() const;
- // Doesn't save().
- h128 readKey(std::string const& _file, bool _deleteFile);
+ /// Import the key from the file @a _file, but do not copy it to the managed directory yet.
+ /// @param _takeFileOwnership if true, deletes the file if it is not the canonical file for the
+ /// key (derived from its uuid).
+ h128 readKey(std::string const& _file, bool _takeFileOwnership);
+ /// Import the key contained in the json-encoded @a _content, but do not store it in the
+ /// managed directory.
+ /// @param _file if given, assume this file contains @a _content and delete it later, if it is
+ /// not the canonical file for the key (derived from the uuid).
h128 readKeyContent(std::string const& _content, std::string const& _file = std::string());
+ /// Store all keys in the directory @a _keysPath.
void save(std::string const& _keysPath);
+ /// Store all keys in the managed directory.
void save() { save(m_path); }
+ /// @returns the default path for the managed directory.
static std::string defaultPath() { return getDataDir("web3") + "/keys"; }
private:
+ struct EncryptedKey
+ {
+ std::string encryptedKey;
+ std::string filename;
+ };
+
+ /// Loads all keys in the given directory.
void load(std::string const& _keysPath);
void load() { load(m_path); }
+ /// Encrypts @a _v with a key derived from @a _pass or the empty string on error.
static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
+ /// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error.
static bytes decrypt(std::string const& _v, std::string const& _pass);
+ /// Stores decrypted keys by uuid.
mutable std::unordered_map m_cached;
- std::unordered_map> m_keys;
+ /// Stores encrypted keys together with the file they were loaded from by uuid.
+ std::unordered_map m_keys;
std::string m_path;
};
diff --git a/libethash-cl/CMakeLists.txt b/libethash-cl/CMakeLists.txt
index fdc2dad07..6da254cfb 100644
--- a/libethash-cl/CMakeLists.txt
+++ b/libethash-cl/CMakeLists.txt
@@ -1,12 +1,23 @@
set(EXECUTABLE ethash-cl)
-include(bin2h.cmake)
-bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
- VARIABLE_NAME ethash_cl_miner_kernel
- HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
+# A custom command and target to turn the OpenCL kernel into a byte array header
+# The normal build depends on it properly and if the kernel file is changed, then
+# a rebuild of libethash-cl should be triggered
+add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h
+ COMMAND ${CMAKE_COMMAND} ARGS
+ -DBIN2H_SOURCE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl"
+ -DBIN2H_VARIABLE_NAME=ethash_cl_miner_kernel
+ -DBIN2H_HEADER_FILE="${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/bin2h.cmake"
+ COMMENT "Generating OpenCL Kernel Byte Array"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl
+)
+add_custom_target(clbin2h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h ${CMAKE_CURRENT_SOURCE_DIR}/ethash_cl_miner_kernel.cl)
aux_source_directory(. SRC_LIST)
-file(GLOB HEADERS "*.h")
+file(GLOB OUR_HEADERS "*.h")
+set(HEADERS ${OUR_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${OpenCL_INCLUDE_DIRS})
diff --git a/libethash-cl/bin2h.cmake b/libethash-cl/bin2h.cmake
index 90ca9cc5b..27ab4eefa 100644
--- a/libethash-cl/bin2h.cmake
+++ b/libethash-cl/bin2h.cmake
@@ -6,31 +6,31 @@ include(CMakeParseArguments)
# VARIABLE - The name of the CMake variable holding the string.
# AT_COLUMN - The column position at which string will be wrapped.
function(WRAP_STRING)
- set(oneValueArgs VARIABLE AT_COLUMN)
- cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
+ set(oneValueArgs VARIABLE AT_COLUMN)
+ cmake_parse_arguments(WRAP_STRING "${options}" "${oneValueArgs}" "" ${ARGN})
- string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
- math(EXPR offset "0")
+ string(LENGTH ${${WRAP_STRING_VARIABLE}} stringLength)
+ math(EXPR offset "0")
- while(stringLength GREATER 0)
+ while(stringLength GREATER 0)
- if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
- math(EXPR length "${WRAP_STRING_AT_COLUMN}")
- else()
- math(EXPR length "${stringLength}")
- endif()
+ if(stringLength GREATER ${WRAP_STRING_AT_COLUMN})
+ math(EXPR length "${WRAP_STRING_AT_COLUMN}")
+ else()
+ math(EXPR length "${stringLength}")
+ endif()
- string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
- set(lines "${lines}\n${line}")
+ string(SUBSTRING ${${WRAP_STRING_VARIABLE}} ${offset} ${length} line)
+ set(lines "${lines}\n${line}")
- math(EXPR stringLength "${stringLength} - ${length}")
- math(EXPR offset "${offset} + ${length}")
- endwhile()
+ math(EXPR stringLength "${stringLength} - ${length}")
+ math(EXPR offset "${offset} + ${length}")
+ endwhile()
- set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
+ set(${WRAP_STRING_VARIABLE} "${lines}" PARENT_SCOPE)
endfunction()
-# Function to embed contents of a file as byte array in C/C++ header file(.h). The header file
+# Script to embed contents of a file as byte array in C/C++ header file(.h). The header file
# will contain a byte array and integer variable holding the size of the array.
# Parameters
# SOURCE_FILE - The path of source file whose contents will be embedded in the header file.
@@ -42,45 +42,41 @@ endfunction()
# useful if the source file is a text file and we want to use the file contents
# as string. But the size variable holds size of the byte array without this
# null byte.
-# Usage:
-# bin2h(SOURCE_FILE "Logo.png" HEADER_FILE "Logo.h" VARIABLE_NAME "LOGO_PNG")
-function(BIN2H)
- set(options APPEND NULL_TERMINATE)
- set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
- cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
+set(options APPEND NULL_TERMINATE)
+set(oneValueArgs SOURCE_FILE VARIABLE_NAME HEADER_FILE)
+# cmake_parse_arguments(BIN2H "${options}" "${oneValueArgs}" "" ${ARGN})
- # reads source file contents as hex string
- file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
- string(LENGTH ${hexString} hexStringLength)
+# reads source file contents as hex string
+file(READ ${BIN2H_SOURCE_FILE} hexString HEX)
+string(LENGTH ${hexString} hexStringLength)
- # appends null byte if asked
- if(BIN2H_NULL_TERMINATE)
- set(hexString "${hexString}00")
- endif()
+# appends null byte if asked
+if(BIN2H_NULL_TERMINATE)
+ set(hexString "${hexString}00")
+endif()
- # wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
- wrap_string(VARIABLE hexString AT_COLUMN 32)
- math(EXPR arraySize "${hexStringLength} / 2")
+# wraps the hex string into multiple lines at column 32(i.e. 16 bytes per line)
+wrap_string(VARIABLE hexString AT_COLUMN 32)
+math(EXPR arraySize "${hexStringLength} / 2")
- # adds '0x' prefix and comma suffix before and after every byte respectively
- string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
- # removes trailing comma
- string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
+# adds '0x' prefix and comma suffix before and after every byte respectively
+string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1, " arrayValues ${hexString})
+# removes trailing comma
+string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
- # converts the variable name into proper C identifier
- IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
- string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
- ENDIF()
- string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
+# converts the variable name into proper C identifier
+IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
+ string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
+ENDIF()
+string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
- # declares byte array and the length variables
- set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
- set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
+# declares byte array and the length variables
+set(arrayDefinition "const unsigned char ${BIN2H_VARIABLE_NAME}[] = { ${arrayValues} };")
+set(arraySizeDefinition "const size_t ${BIN2H_VARIABLE_NAME}_SIZE = ${arraySize};")
- set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
- if(BIN2H_APPEND)
- file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
- else()
- file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
- endif()
-endfunction()
+set(declarations "${arrayDefinition}\n\n${arraySizeDefinition}\n\n")
+if(BIN2H_APPEND)
+ file(APPEND ${BIN2H_HEADER_FILE} "${declarations}")
+else()
+ file(WRITE ${BIN2H_HEADER_FILE} "${declarations}")
+endif()
diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp
index 6c2f8269a..315f29685 100644
--- a/libethash-cl/ethash_cl_miner.cpp
+++ b/libethash-cl/ethash_cl_miner.cpp
@@ -140,12 +140,10 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId)
bool ethash_cl_miner::configureGPU(
bool _allowCPU,
unsigned _extraGPUMemory,
- bool _forceSingleChunk,
boost::optional _currentBlock
)
{
s_allowCPU = _allowCPU;
- s_forceSingleChunk = _forceSingleChunk;
s_extraRequiredGPUMem = _extraGPUMemory;
// by default let's only consider the DAG of the first epoch
uint64_t dagSize = _currentBlock ? ethash_get_datasize(*_currentBlock) : 1073739904U;
@@ -174,7 +172,6 @@ bool ethash_cl_miner::configureGPU(
}
bool ethash_cl_miner::s_allowCPU = false;
-bool ethash_cl_miner::s_forceSingleChunk = false;
unsigned ethash_cl_miner::s_extraRequiredGPUMem;
bool ethash_cl_miner::searchForAllDevices(function _callback)
@@ -288,23 +285,6 @@ bool ethash_cl_miner::init(
string device_version = device.getInfo();
ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")");
- // configure chunk number depending on max allocateable memory
- cl_ulong result;
- device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result);
- if (s_forceSingleChunk || result >= _dagSize)
- {
- m_dagChunksNum = 1;
- ETHCL_LOG(
- ((result <= _dagSize && s_forceSingleChunk) ? "Forcing single chunk. Good luck!\n" : "") <<
- "Using 1 big chunk. Max OpenCL allocateable memory is " << result
- );
- }
- else
- {
- m_dagChunksNum = 4;
- ETHCL_LOG("Using 4 chunks. Max OpenCL allocateable memory is " << result);
- }
-
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{
ETHCL_LOG("OpenCL 1.0 is not supported.");
@@ -341,31 +321,32 @@ bool ethash_cl_miner::init(
ETHCL_LOG("Printing program log");
ETHCL_LOG(program.getBuildInfo(device).c_str());
}
- catch (cl::Error err)
+ catch (cl::Error const& err)
{
ETHCL_LOG(program.getBuildInfo(device).c_str());
return false;
}
- if (m_dagChunksNum == 1)
- {
- ETHCL_LOG("Loading single big chunk kernels");
- m_hash_kernel = cl::Kernel(program, "ethash_hash");
- m_search_kernel = cl::Kernel(program, "ethash_search");
- }
- else
- {
- ETHCL_LOG("Loading chunk kernels");
- m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks");
- m_search_kernel = cl::Kernel(program, "ethash_search_chunks");
- }
// create buffer for dag
- if (m_dagChunksNum == 1)
+ try
{
- ETHCL_LOG("Creating one big buffer");
+ m_dagChunksNum = 1;
m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize));
+ ETHCL_LOG("Created one big buffer for the DAG");
}
- else
+ catch (cl::Error const& err)
+ {
+ int errCode = err.err();
+ if (errCode != CL_INVALID_BUFFER_SIZE || errCode != CL_MEM_OBJECT_ALLOCATION_FAILURE)
+ ETHCL_LOG("Allocating single buffer failed with: " << err.what() << "(" << errCode << ")");
+ cl_ulong result;
+ device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result);
+ ETHCL_LOG(
+ "Failed to allocate 1 big chunk. Max allocateable memory is "
+ << result << ". Trying to allocate 4 chunks."
+ );
+ // The OpenCL kernel has a hard coded number of 4 chunks at the moment
+ m_dagChunksNum = 4;
for (unsigned i = 0; i < m_dagChunksNum; i++)
{
// TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation
@@ -376,6 +357,20 @@ bool ethash_cl_miner::init(
(i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7
));
}
+ }
+
+ if (m_dagChunksNum == 1)
+ {
+ ETHCL_LOG("Loading single big chunk kernels");
+ m_hash_kernel = cl::Kernel(program, "ethash_hash");
+ m_search_kernel = cl::Kernel(program, "ethash_search");
+ }
+ else
+ {
+ ETHCL_LOG("Loading chunk kernels");
+ m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks");
+ m_search_kernel = cl::Kernel(program, "ethash_search_chunks");
+ }
// create buffer for header
ETHCL_LOG("Creating buffer for header.");
@@ -410,7 +405,7 @@ bool ethash_cl_miner::init(
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
}
}
- catch (cl::Error err)
+ catch (cl::Error const& err)
{
ETHCL_LOG(err.what() << "(" << err.err() << ")");
return false;
@@ -429,7 +424,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
};
queue pending;
- static uint32_t const c_zero = 0;
+ // this can't be a static because in MacOSX OpenCL implementation a segfault occurs when a static is passed to OpenCL functions
+ uint32_t const c_zero = 0;
// update header constant buffer
m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header);
@@ -503,7 +499,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
pre_return_event.wait();
#endif
}
- catch (cl::Error err)
+ catch (cl::Error const& err)
{
ETHCL_LOG(err.what() << "(" << err.err() << ")");
}
diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h
index cc01b0057..f36082a5a 100644
--- a/libethash-cl/ethash_cl_miner.h
+++ b/libethash-cl/ethash_cl_miner.h
@@ -44,7 +44,6 @@ public:
static bool configureGPU(
bool _allowCPU,
unsigned _extraGPUMemory,
- bool _forceSingleChunk,
boost::optional _currentBlock
);
@@ -79,8 +78,6 @@ private:
unsigned m_workgroup_size;
bool m_opencl_1_1;
- /// Force dag upload to GPU in a single chunk even if OpenCL thinks you can't do it. Use at your own risk.
- static bool s_forceSingleChunk;
/// Allow CPU to appear as an OpenCL device or not. Default is false
static bool s_allowCPU;
/// GPU memory required for other things, like window rendering e.t.c.
diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl
index 2143435ed..8ea6df12d 100644
--- a/libethash-cl/ethash_cl_miner_kernel.cl
+++ b/libethash-cl/ethash_cl_miner_kernel.cl
@@ -36,7 +36,7 @@ __constant uint2 const Keccak_f1600_RC[24] = {
(uint2)(0x80008008, 0x80000000),
};
-void keccak_f1600_round(uint2* a, uint r, uint out_size)
+static void keccak_f1600_round(uint2* a, uint r, uint out_size)
{
#if !__ENDIAN_LITTLE__
for (uint i = 0; i != 25; ++i)
@@ -152,7 +152,7 @@ void keccak_f1600_round(uint2* a, uint r, uint out_size)
#endif
}
-void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
+static void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
{
for (uint i = in_size; i != 25; ++i)
{
@@ -194,17 +194,17 @@ void keccak_f1600_no_absorb(ulong* a, uint in_size, uint out_size, uint isolate)
#define countof(x) (sizeof(x) / sizeof(x[0]))
-uint fnv(uint x, uint y)
+static uint fnv(uint x, uint y)
{
return x * FNV_PRIME ^ y;
}
-uint4 fnv4(uint4 x, uint4 y)
+static uint4 fnv4(uint4 x, uint4 y)
{
return x * FNV_PRIME ^ y;
}
-uint fnv_reduce(uint4 v)
+static uint fnv_reduce(uint4 v)
{
return fnv(fnv(fnv(v.x, v.y), v.z), v.w);
}
@@ -227,7 +227,7 @@ typedef union
uint4 uint4s[128 / sizeof(uint4)];
} hash128_t;
-hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
+static hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
{
hash64_t init;
uint const init_size = countof(init.ulongs);
@@ -243,7 +243,7 @@ hash64_t init_hash(__constant hash32_t const* header, ulong nonce, uint isolate)
return init;
}
-uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
+static uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, __global hash128_t const* g_dag1, __global hash128_t const* g_dag2, __global hash128_t const* g_dag3, uint isolate)
{
uint4 mix = init;
@@ -277,7 +277,7 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global
-uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
+static uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate)
{
uint4 mix = init;
@@ -311,7 +311,7 @@ uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash12
}
-hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
+static hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
{
ulong state[25];
@@ -330,7 +330,7 @@ hash32_t final_hash(hash64_t const* init, hash32_t const* mix, uint isolate)
return hash;
}
-hash32_t compute_hash_simple(
+static hash32_t compute_hash_simple(
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
ulong nonce,
@@ -383,7 +383,7 @@ typedef union
} compute_hash_share;
-hash32_t compute_hash(
+static hash32_t compute_hash(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
@@ -427,7 +427,7 @@ hash32_t compute_hash(
}
-hash32_t compute_hash_chunks(
+static hash32_t compute_hash_chunks(
__local compute_hash_share* share,
__constant hash32_t const* g_header,
__global hash128_t const* g_dag,
diff --git a/libethash/endian.h b/libethash/endian.h
index 0ee402d9a..6ca6cc036 100644
--- a/libethash/endian.h
+++ b/libethash/endian.h
@@ -32,6 +32,9 @@
#include
#define ethash_swap_u32(input_) OSSwapInt32(input_)
#define ethash_swap_u64(input_) OSSwapInt64(input_)
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
+#define ethash_swap_u32(input_) bswap32(input_)
+#define ethash_swap_u64(input_) bswap64(input_)
#else // posix
#include
#define ethash_swap_u32(input_) __bswap_32(input_)
diff --git a/libethash/internal.c b/libethash/internal.c
index 26378e56e..a050d5b48 100644
--- a/libethash/internal.c
+++ b/libethash/internal.c
@@ -284,13 +284,13 @@ bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
- return ethash_check_difficulty(&return_hash, difficulty);
+ return ethash_check_difficulty(&return_hash, boundary);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
diff --git a/libethash/internal.h b/libethash/internal.h
index 4e2b695ac..26c395ad6 100644
--- a/libethash/internal.h
+++ b/libethash/internal.h
@@ -46,27 +46,36 @@ static inline void ethash_h256_reset(ethash_h256_t* hash)
memset(hash, 0, 32);
}
-// Returns if hash is less than or equal to difficulty
+// Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
)
{
- // Difficulty is big endian
+ // Boundary is big endian
for (int i = 0; i < 32; i++) {
- if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) {
+ if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue;
}
- return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i);
+ return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
}
return true;
}
+/**
+ * Difficulty quick check for POW preverification
+ *
+ * @param header_hash The hash of the header
+ * @param nonce The block's nonce
+ * @param mix_hash The mix digest hash
+ * @param boundary The boundary is defined as (2^256 / difficulty)
+ * @return true for succesful pre-verification and false otherwise
+ */
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
- ethash_h256_t const* difficulty
+ ethash_h256_t const* boundary
);
struct ethash_light {
diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp
index 69da52b09..fec5b4678 100644
--- a/libethcore/BlockInfo.cpp
+++ b/libethcore/BlockInfo.cpp
@@ -122,7 +122,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
try
{
if (_header.itemCount() != 15)
- throw InvalidBlockHeaderItemCount();
+ BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
parentHash = _header[field = 0].toHash(RLP::VeryStrict);
sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict);
coinbaseAddress = _header[field = 2].toHash(RLP::VeryStrict);
@@ -146,7 +146,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const
}
if (number > ~(unsigned)0)
- throw InvalidNumber();
+ BOOST_THROW_EXCEPTION(InvalidNumber());
// check it hashes according to proof of work or that it's the genesis block.
if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this))
diff --git a/libethcore/Common.h b/libethcore/Common.h
index 6f23cb0e8..19ca600b9 100644
--- a/libethcore/Common.h
+++ b/libethcore/Common.h
@@ -47,7 +47,8 @@ extern const unsigned c_databaseVersion;
enum class Network
{
Olympic = 0,
- Frontier = 1
+ Frontier = 1,
+ Turbo = 2
};
extern const Network c_network;
@@ -100,7 +101,8 @@ enum class ImportResult
{
Success = 0,
UnknownParent,
- FutureTime,
+ FutureTimeKnown,
+ FutureTimeUnknown,
AlreadyInChain,
AlreadyKnown,
Malformed,
diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp
index 2c743f33b..b277e3c1c 100644
--- a/libethcore/Ethash.cpp
+++ b/libethcore/Ethash.cpp
@@ -108,7 +108,10 @@ bool Ethash::verify(BlockInfo const& _header)
bool pre = preVerify(_header);
#if !ETH_DEBUG
if (!pre)
+ {
+ cwarn << "Fail on preVerify";
return false;
+ }
#endif
auto result = EthashAux::eval(_header);
@@ -386,13 +389,12 @@ bool Ethash::GPUMiner::configureGPU(
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
- bool _forceSingleChunk,
boost::optional _currentBlock
)
{
s_platformId = _platformId;
s_deviceId = _deviceId;
- return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _forceSingleChunk, _currentBlock);
+ return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _currentBlock);
}
#endif
diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h
index a5a7856f1..11e012df5 100644
--- a/libethcore/Ethash.h
+++ b/libethcore/Ethash.h
@@ -88,7 +88,7 @@ public:
static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); }
static std::string platformInfo();
static void listDevices() {}
- static bool configureGPU(unsigned, unsigned, bool, unsigned, bool, boost::optional) { return false; }
+ static bool configureGPU(unsigned, unsigned, bool, unsigned, boost::optional) { return false; }
static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); }
protected:
void kickOff() override
@@ -122,7 +122,6 @@ public:
unsigned _deviceId,
bool _allowCPU,
unsigned _extraGPUMemory,
- bool _forceSingleChunk,
boost::optional _currentBlock
);
static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); }
diff --git a/libethcore/Farm.h b/libethcore/Farm.h
index 9acb375ad..581f8bd60 100644
--- a/libethcore/Farm.h
+++ b/libethcore/Farm.h
@@ -68,6 +68,7 @@ public:
void setWork(WorkPackage const& _wp)
{
WriteGuard l(x_minerWork);
+ cdebug << "Farm::setWork()";
if (_wp.headerHash == m_work.headerHash)
return;
m_work = _wp;
@@ -94,6 +95,7 @@ public:
void stop()
{
WriteGuard l(x_minerWork);
+ cdebug << "Farm::stop()";
m_miners.clear();
m_work.reset();
m_isMining = false;
@@ -175,6 +177,7 @@ private:
bool start()
{
WriteGuard l(x_minerWork);
+ cdebug << "start()";
if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0]))
return true;
m_miners.clear();
diff --git a/libethcore/ICAP.cpp b/libethcore/ICAP.cpp
index 158c297f8..12e8aed56 100644
--- a/libethcore/ICAP.cpp
+++ b/libethcore/ICAP.cpp
@@ -71,7 +71,7 @@ ICAP ICAP::decoded(std::string const& _encoded)
std::string data;
std::tie(country, data) = fromIBAN(_encoded);
if (country != "XE")
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
if (data.size() == 30)
{
ret.m_type = Direct;
@@ -88,10 +88,10 @@ ICAP ICAP::decoded(std::string const& _encoded)
ret.m_client = data.substr(7);
}
else
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
}
else
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
return ret;
}
@@ -101,7 +101,7 @@ std::string ICAP::encoded() const
if (m_type == Direct)
{
if (!!m_direct[0])
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
std::string d = toBase36(m_direct);
while (d.size() < 30)
d = "0" + d;
@@ -118,11 +118,11 @@ std::string ICAP::encoded() const
m_institution.size() != 4 ||
m_client.size() != 9
)
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
return iban("XE", m_asset + m_institution + m_client);
}
else
- throw InvalidICAP();
+ BOOST_THROW_EXCEPTION(InvalidICAP());
}
pair ICAP::lookup(std::function const& _call, Address const& _reg) const
@@ -149,9 +149,9 @@ pair ICAP::lookup(std::function const& _c
else if (m_institution[0] != 'X')
return make_pair(resolve(m_institution + "/" + m_client), bytes());
else
- throw InterfaceNotSupported("ICAP::lookup(), bad institution");
+ BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad institution"));
}
- throw InterfaceNotSupported("ICAP::lookup(), bad asset");
+ BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad asset"));
}
}
diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp
index 4430a588e..602c60b4a 100644
--- a/libethcore/KeyManager.cpp
+++ b/libethcore/KeyManager.cpp
@@ -31,7 +31,7 @@ using namespace dev;
using namespace eth;
namespace fs = boost::filesystem;
-KeyManager::KeyManager(std::string const& _keysFile, std::string const& _secretsPath):
+KeyManager::KeyManager(string const& _keysFile, string const& _secretsPath):
m_keysFile(_keysFile), m_store(_secretsPath)
{}
@@ -43,13 +43,13 @@ bool KeyManager::exists() const
return !contents(m_keysFile + ".salt").empty() && !contents(m_keysFile).empty();
}
-void KeyManager::create(std::string const& _pass)
+void KeyManager::create(string const& _pass)
{
- m_password = asString(h256::random().asBytes());
+ m_defaultPasswordDeprecated = asString(h256::random().asBytes());
write(_pass, m_keysFile);
}
-bool KeyManager::recode(Address const& _address, std::string const& _newPass, std::string const& _hint, std::function const& _pass, KDF _kdf)
+bool KeyManager::recode(Address const& _address, string const& _newPass, string const& _hint, function const& _pass, KDF _kdf)
{
noteHint(_newPass, _hint);
h128 u = uuid(_address);
@@ -61,10 +61,10 @@ bool KeyManager::recode(Address const& _address, std::string const& _newPass, st
return true;
}
-bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass, KDF _kdf)
+bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, function const& _pass, KDF _kdf)
{
h128 u = uuid(_address);
- std::string p;
+ string p;
if (_newPass == SemanticPassword::Existing)
p = getPassword(u, _pass);
else if (_newPass == SemanticPassword::Master)
@@ -75,41 +75,47 @@ bool KeyManager::recode(Address const& _address, SemanticPassword _newPass, std:
return recode(_address, p, string(), _pass, _kdf);
}
-bool KeyManager::load(std::string const& _pass)
+bool KeyManager::load(string const& _pass)
{
- try {
+ try
+ {
bytes salt = contents(m_keysFile + ".salt");
bytes encKeys = contents(m_keysFile);
- m_key = h128(pbkdf2(_pass, salt, 262144, 16));
- bytes bs = decryptSymNoAuth(m_key, h128(), &encKeys);
+ m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16));
+ bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
RLP s(bs);
- unsigned version = (unsigned)s[0];
+ unsigned version = unsigned(s[0]);
if (version == 1)
{
for (auto const& i: s[1])
{
- m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]);
-// cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3];
+ h128 uuid(i[1]);
+ Address addr(i[0]);
+ m_addrLookup[addr] = uuid;
+ m_keyInfo[uuid] = KeyInfo(h256(i[2]), string(i[3]));
+// cdebug << toString(addr) << toString(uuid) << toString((h256)i[2]) << (string)i[3];
}
for (auto const& i: s[2])
- m_passwordInfo[(h256)i[0]] = (std::string)i[1];
- m_password = (string)s[3];
+ m_passwordHint[h256(i[0])] = string(i[1]);
+ m_defaultPasswordDeprecated = string(s[3]);
}
// cdebug << hashPassword(m_password) << toHex(m_password);
- m_cachedPasswords[hashPassword(m_password)] = m_password;
+ cachePassword(m_defaultPasswordDeprecated);
// cdebug << hashPassword(asString(m_key.ref())) << m_key.hex();
- m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref());
+ cachePassword(asString(m_keysFileKey.ref()));
// cdebug << hashPassword(_pass) << _pass;
- m_cachedPasswords[m_master = hashPassword(_pass)] = _pass;
+ m_master = hashPassword(_pass);
+ cachePassword(_pass);
return true;
}
- catch (...) {
+ catch (...)
+ {
return false;
}
}
-Secret KeyManager::secret(Address const& _address, function const& _pass) const
+Secret KeyManager::secret(Address const& _address, function const& _pass) const
{
auto it = m_addrLookup.find(_address);
if (it == m_addrLookup.end())
@@ -117,12 +123,12 @@ Secret KeyManager::secret(Address const& _address, function const
return secret(it->second, _pass);
}
-Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const
+Secret KeyManager::secret(h128 const& _uuid, function const& _pass) const
{
return Secret(m_store.secret(_uuid, [&](){ return getPassword(_uuid, _pass); }));
}
-std::string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const
+string KeyManager::getPassword(h128 const& _uuid, function const& _pass) const
{
auto kit = m_keyInfo.find(_uuid);
h256 ph;
@@ -131,19 +137,19 @@ std::string KeyManager::getPassword(h128 const& _uuid, function c
return getPassword(ph, _pass);
}
-std::string KeyManager::getPassword(h256 const& _passHash, function const& _pass) const
+string KeyManager::getPassword(h256 const& _passHash, function const& _pass) const
{
auto it = m_cachedPasswords.find(_passHash);
if (it != m_cachedPasswords.end())
return it->second;
- for (unsigned i = 0; i< 10; ++i)
+ for (unsigned i = 0; i < 10; ++i)
{
- std::string p = _pass();
+ string p = _pass();
if (p.empty())
break;
- if (hashPassword(p) == _passHash || _passHash == UnknownPassword)
+ if (_passHash == UnknownPassword || hashPassword(p) == _passHash)
{
- m_cachedPasswords[hashPassword(p)] = p;
+ cachePassword(p);
return p;
}
}
@@ -166,20 +172,20 @@ Address KeyManager::address(h128 const& _uuid) const
return Address();
}
-h128 KeyManager::import(Secret const& _s, string const& _info, std::string const& _pass, string const& _passInfo)
+h128 KeyManager::import(Secret const& _s, string const& _accountName, string const& _pass, string const& _passwordHint)
{
Address addr = KeyPair(_s).address();
auto passHash = hashPassword(_pass);
- m_cachedPasswords[passHash] = _pass;
- m_passwordInfo[passHash] = _passInfo;
+ cachePassword(_pass);
+ m_passwordHint[passHash] = _passwordHint;
auto uuid = m_store.importSecret(_s.asBytes(), _pass);
- m_keyInfo[uuid] = KeyInfo{passHash, _info};
+ m_keyInfo[uuid] = KeyInfo{passHash, _accountName};
m_addrLookup[addr] = uuid;
write(m_keysFile);
return uuid;
}
-void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo)
+void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
{
bytes key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty())
@@ -187,17 +193,17 @@ void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, std
Address a = KeyPair(Secret(key)).address();
auto passHash = hashPassword(_pass);
if (!m_cachedPasswords.count(passHash))
- m_cachedPasswords[passHash] = _pass;
- importExisting(_uuid, _info, a, passHash, _passInfo);
+ cachePassword(_pass);
+ importExisting(_uuid, _info, a, passHash, _passwordHint);
}
-void KeyManager::importExisting(h128 const& _uuid, std::string const& _info, Address const& _address, h256 const& _passHash, std::string const& _passInfo)
+void KeyManager::importExisting(h128 const& _uuid, string const& _accountName, Address const& _address, h256 const& _passHash, string const& _passwordHint)
{
- if (!m_passwordInfo.count(_passHash))
- m_passwordInfo[_passHash] = _passInfo;
+ if (!m_passwordHint.count(_passHash))
+ m_passwordHint[_passHash] = _passwordHint;
m_addrLookup[_address] = _uuid;
m_keyInfo[_uuid].passHash = _passHash;
- m_keyInfo[_uuid].info = _info;
+ m_keyInfo[_uuid].accountName = _accountName;
write(m_keysFile);
}
@@ -209,67 +215,92 @@ void KeyManager::kill(Address const& _a)
m_store.kill(id);
}
-AddressHash KeyManager::accounts() const
+Addresses KeyManager::accounts() const
{
- AddressHash ret;
+ Addresses ret;
+ ret.reserve(m_addrLookup.size());
for (auto const& i: m_addrLookup)
if (m_keyInfo.count(i.second) > 0)
- ret.insert(i.first);
+ ret.push_back(i.first);
return ret;
}
-std::unordered_map> KeyManager::accountDetails() const
+bool KeyManager::hasAccount(const Address& _address) const
{
- std::unordered_map> ret;
- for (auto const& i: m_addrLookup)
- if (m_keyInfo.count(i.second) > 0)
- ret[i.first] = make_pair(m_keyInfo.count(i.second) ? m_keyInfo.at(i.second).info : "", m_keyInfo.count(i.second) && m_passwordInfo.count(m_keyInfo.at(i.second).passHash) ? m_passwordInfo.at(m_keyInfo.at(i.second).passHash) : "");
- return ret;
+ return m_addrLookup.count(_address) && m_keyInfo.count(m_addrLookup.at(_address));
+}
+
+string const& KeyManager::accountName(Address const& _address) const
+{
+ try
+ {
+ return m_keyInfo.at(m_addrLookup.at(_address)).accountName;
+ }
+ catch (...)
+ {
+ return EmptyString;
+ }
+}
+
+string const& KeyManager::passwordHint(Address const& _address) const
+{
+ try
+ {
+ return m_passwordHint.at(m_keyInfo.at(m_addrLookup.at(_address)).passHash);
+ }
+ catch (...)
+ {
+ return EmptyString;
+ }
}
-h256 KeyManager::hashPassword(std::string const& _pass) const
+h256 KeyManager::hashPassword(string const& _pass) const
{
// TODO SECURITY: store this a bit more securely; Scrypt perhaps?
- return h256(pbkdf2(_pass, asBytes(m_password), 262144, 32));
+ return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32));
+}
+
+void KeyManager::cachePassword(string const& _password) const
+{
+ m_cachedPasswords[hashPassword(_password)] = _password;
}
-bool KeyManager::write(std::string const& _keysFile) const
+bool KeyManager::write(string const& _keysFile) const
{
- if (!m_key)
+ if (!m_keysFileKey)
return false;
- write(m_key, _keysFile);
+ write(m_keysFileKey, _keysFile);
return true;
}
-void KeyManager::write(std::string const& _pass, std::string const& _keysFile) const
+void KeyManager::write(string const& _pass, string const& _keysFile) const
{
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
- m_cachedPasswords[hashPassword(_pass)] = _pass;
+ cachePassword(_pass);
m_master = hashPassword(_pass);
write(key, _keysFile);
}
-void KeyManager::write(h128 const& _key, std::string const& _keysFile) const
+void KeyManager::write(h128 const& _key, string const& _keysFile) const
{
RLPStream s(4);
- s << 1;
- s.appendList(m_addrLookup.size());
- for (auto const& i: m_addrLookup)
- if (m_keyInfo.count(i.second))
- {
- auto ki = m_keyInfo.at(i.second);
- s.appendList(4) << i.first << i.second << ki.passHash << ki.info;
- }
- s.appendList(m_passwordInfo.size());
- for (auto const& i: m_passwordInfo)
+ s << 1; // version
+ s.appendList(accounts().size());
+ for (auto const& address: accounts())
+ {
+ h128 id = uuid(address);
+ auto const& ki = m_keyInfo.at(id);
+ s.appendList(4) << address << id << ki.passHash << ki.accountName;
+ }
+ s.appendList(m_passwordHint.size());
+ for (auto const& i: m_passwordHint)
s.appendList(2) << i.first << i.second;
- s.append(m_password);
+ s.append(m_defaultPasswordDeprecated);
writeFile(_keysFile, encryptSymNoAuth(_key, h128(), &s.out()));
- m_key = _key;
- m_cachedPasswords[hashPassword(defaultPassword())] = defaultPassword();
-
+ m_keysFileKey = _key;
+ cachePassword(defaultPassword());
}
diff --git a/libethcore/KeyManager.h b/libethcore/KeyManager.h
index 62263c3c5..0e54f3f42 100644
--- a/libethcore/KeyManager.h
+++ b/libethcore/KeyManager.h
@@ -23,8 +23,9 @@
#include
#include
-#include
#include
+#include
+#include
namespace dev
{
@@ -35,14 +36,17 @@ class PasswordUnknown: public Exception {};
struct KeyInfo
{
KeyInfo() = default;
- KeyInfo(h256 const& _passHash, std::string const& _info): passHash(_passHash), info(_info) {}
+ KeyInfo(h256 const& _passHash, std::string const& _accountName): passHash(_passHash), accountName(_accountName) {}
- h256 passHash; ///< Hash of the password or h256() if unknown.
- std::string info; ///< Name of the key, or JSON key info if begins with '{'.
+ /// Hash of the password or h256() / UnknownPassword if unknown.
+ h256 passHash;
+ /// Name of the key, or JSON key info if begins with '{'.
+ std::string accountName;
};
-static const h256 UnknownPassword;
-static const auto DontKnowThrow = [](){ throw PasswordUnknown(); return std::string(); };
+static h256 const UnknownPassword;
+/// Password query function that never returns a password.
+static auto const DontKnowThrow = [](){ BOOST_THROW_EXCEPTION(PasswordUnknown()); return std::string(); };
enum class SemanticPassword
{
@@ -53,12 +57,15 @@ enum class SemanticPassword
// TODO: This one is specifically for Ethereum, but we can make it generic in due course.
// TODO: hidden-partition style key-store.
/**
- * @brief High-level manager of keys for Ethereum.
+ * @brief High-level manager of password-encrypted keys for Ethereum.
* Usage:
*
* Call exists() to check whether there is already a database. If so, get the master password from
* the user and call load() with it. If not, get a new master password from the user (get them to type
* it twice and keep some hint around!) and call create() with it.
+ *
+ * Uses a "key file" (and a corresponding .salt file) that contains encrypted information about the keys and
+ * a directory called "secrets path" that contains a file for each key.
*/
class KeyManager
{
@@ -75,25 +82,37 @@ public:
void save(std::string const& _pass) const { write(_pass, m_keysFile); }
void notePassword(std::string const& _pass) { m_cachedPasswords[hashPassword(_pass)] = _pass; }
- void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordInfo[hashPassword(_pass)] = _hint; }
+ void noteHint(std::string const& _pass, std::string const& _hint) { if (!_hint.empty()) m_passwordHint[hashPassword(_pass)] = _hint; }
bool haveHint(std::string const& _pass) const { auto h = hashPassword(_pass); return m_cachedPasswords.count(h) && !m_cachedPasswords.at(h).empty(); }
- AddressHash accounts() const;
- std::unordered_map> accountDetails() const;
- std::string const& hint(Address const& _a) const { try { return m_passwordInfo.at(m_keyInfo.at(m_addrLookup.at(_a)).passHash); } catch (...) { return EmptyString; } }
-
+ /// @returns the list of account addresses.
+ Addresses accounts() const;
+ /// @returns a hashset of all account addresses.
+ AddressHash accountsHash() const { return AddressHash() + accounts(); }
+ bool hasAccount(Address const& _address) const;
+ /// @returns the human-readable name or json-encoded info of the account for the given address.
+ std::string const& accountName(Address const& _address) const;
+ /// @returns the password hint for the account for the given address;
+ std::string const& passwordHint(Address const& _address) const;
+
+ /// @returns the uuid of the key for the address @a _a or the empty hash on error.
h128 uuid(Address const& _a) const;
+ /// @returns the address corresponding to the key with uuid @a _uuid or the zero address on error.
Address address(h128 const& _uuid) const;
- h128 import(Secret const& _s, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
- h128 import(Secret const& _s, std::string const& _info) { return import(_s, _info, defaultPassword(), std::string()); }
+ h128 import(Secret const& _s, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint);
+ h128 import(Secret const& _s, std::string const& _accountName) { return import(_s, _accountName, defaultPassword(), std::string()); }
SecretStore& store() { return m_store; }
- void importExisting(h128 const& _uuid, std::string const& _info, std::string const& _pass, std::string const& _passInfo);
- void importExisting(h128 const& _uuid, std::string const& _info) { importExisting(_uuid, _info, defaultPassword(), std::string()); }
- void importExisting(h128 const& _uuid, std::string const& _info, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passInfo = std::string());
+ void importExisting(h128 const& _uuid, std::string const& _accountName, std::string const& _pass, std::string const& _passwordHint);
+ void importExisting(h128 const& _uuid, std::string const& _accountName) { importExisting(_uuid, _accountName, defaultPassword(), std::string()); }
+ void importExisting(h128 const& _uuid, std::string const& _accountName, Address const& _addr, h256 const& _passHash = h256(), std::string const& _passwordHint = std::string());
+ /// @returns the secret key associated with an address provided the password query
+ /// function @a _pass or the zero-secret key on error.
Secret secret(Address const& _address, std::function const& _pass = DontKnowThrow) const;
+ /// @returns the secret key associated with the uuid of a key provided the password query
+ /// function @a _pass or the zero-secret key on error.
Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const;
bool recode(Address const& _address, SemanticPassword _newPass, std::function const& _pass = DontKnowThrow, KDF _kdf = KDF::Scrypt);
@@ -110,6 +129,9 @@ private:
std::string defaultPassword(std::function const& _pass = DontKnowThrow) const { return getPassword(m_master, _pass); }
h256 hashPassword(std::string const& _pass) const;
+ /// Stores the password by its hash in the password cache.
+ void cachePassword(std::string const& _password) const;
+
// Only use if previously loaded ok.
// @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); }
@@ -118,11 +140,15 @@ private:
void write(h128 const& _key, std::string const& _keysFile) const;
// Ethereum keys.
+
+ /// Mapping address -> key uuid.
std::unordered_map m_addrLookup;
+ /// Mapping key uuid -> key info.
std::unordered_map m_keyInfo;
- std::unordered_map m_passwordInfo;
+ /// Mapping password hash -> password hint.
+ std::unordered_map m_passwordHint;
- // Passwords that we're storing.
+ // Passwords that we're storing. Mapping password hash -> password.
mutable std::unordered_map m_cachedPasswords;
// DEPRECATED.
@@ -130,10 +156,10 @@ private:
// Now the default password is based off the key of the keys file directly, so this is redundant
// except for the fact that people have existing keys stored with it. Leave for now until/unless
// we have an upgrade strategy.
- std::string m_password;
+ std::string m_defaultPasswordDeprecated;
mutable std::string m_keysFile;
- mutable h128 m_key;
+ mutable h128 m_keysFileKey;
mutable h256 m_master;
SecretStore m_store;
};
diff --git a/libethcore/Params.cpp b/libethcore/Params.cpp
index 916adf6ca..0fea39b30 100644
--- a/libethcore/Params.cpp
+++ b/libethcore/Params.cpp
@@ -31,12 +31,12 @@ namespace eth
//--- BEGIN: AUTOGENERATED FROM github.com/ethereum/common/params.json
u256 const c_genesisDifficulty = 131072;
u256 const c_maximumExtraDataSize = 1024;
-u256 const c_genesisGasLimit = 3141592;
-u256 const c_minGasLimit = 125000;
+u256 const c_genesisGasLimit = c_network == Network::Turbo ? 100000000 : 3141592;
+u256 const c_minGasLimit = c_network == Network::Turbo ? 100000000 : 125000;
u256 const c_gasLimitBoundDivisor = 1024;
u256 const c_minimumDifficulty = 131072;
u256 const c_difficultyBoundDivisor = 2048;
-u256 const c_durationLimit = c_network == Network::Olympic ? 8 : 12;
+u256 const c_durationLimit = c_network == Network::Turbo ? 2 : c_network == Network::Olympic ? 8 : 12;
//--- END: AUTOGENERATED FROM /feeStructure.json
}
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index bd6996a45..640fd2df4 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -24,8 +24,6 @@
#if ETH_PROFILING_GPERF
#include
#endif
-#include
-#include
#include
#include
#include
@@ -305,7 +303,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const
return m_lastLastHashes;
}
-tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
+tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max)
{
// _bq.tick(*this);
@@ -315,6 +313,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st
h256s fresh;
h256s dead;
h256s badBlocks;
+ unsigned count = 0;
for (VerifiedBlock const& block: blocks)
if (!badBlocks.empty())
badBlocks.push_back(block.verified.info.hash());
@@ -326,8 +325,9 @@ tuple