From e241db70a8912471ac5ea4d91e57482d4d54b61d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 5 Mar 2015 15:58:20 +0100 Subject: [PATCH] For Marek :) BlockChain::transaction(h256 _transactionHash) BlockChain::transactionHashes(h256 _blockHash) --- alethzero/MainWin.cpp | 4 +- libethcore/ProofOfWork.cpp | 98 ++------------------------------------ libethcore/ProofOfWork.h | 10 ---- libethereum/BlockChain.cpp | 19 ++++---- libethereum/BlockChain.h | 32 +++---------- libethereum/BlockDetails.h | 14 +++++- test/dagger.cpp | 22 ++++----- 7 files changed, 47 insertions(+), 152 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index a096d2c15..b79bc6e83 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1410,7 +1410,7 @@ void Main::on_blocks_currentItemChanged() s << "
Difficulty: " << info.difficulty << ""; if (info.number) { - auto e = ProofOfWork::eval(info); + auto e = Ethasher::eval(info); s << "
Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / info.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")"; } else @@ -1434,7 +1434,7 @@ void Main::on_blocks_currentItemChanged() s << line << "Nonce: " << uncle.nonce << ""; s << line << "Hash w/o nonce: " << uncle.headerHash(WithoutNonce) << ""; s << line << "Difficulty: " << uncle.difficulty << ""; - auto e = ProofOfWork::eval(uncle); + auto e = Ethasher::eval(uncle); s << line << "Proof-of-Work: " << e.value << " <= " << (h256)u256((bigint(1) << 256) / uncle.difficulty) << " (mixhash: " << e.mixHash.abridged() << ")"; } if (info.parentHash) diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index c879df2ce..d261ccb1c 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -30,8 +30,8 @@ #include #include #include -#include #include "BlockInfo.h" +#include "Ethasher.h" #include "ProofOfWork.h" using namespace std; using namespace std::chrono; @@ -41,100 +41,14 @@ namespace dev namespace eth { -class Ethasher -{ -public: - Ethasher() {} - - static Ethasher* get() { if (!s_this) s_this = new Ethasher(); return s_this; } - - bytes const& cache(BlockInfo const& _header) - { - RecursiveGuard l(x_this); - if (!m_caches.count(_header.seedHash)) - { - try { - boost::filesystem::create_directories(getDataDir() + "/ethashcache"); - } catch (...) {} - std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".cache"; - m_caches[_header.seedHash] = contents(memoFile); - if (m_caches[_header.seedHash].empty()) - { - ethash_params p = params((unsigned)_header.number); - m_caches[_header.seedHash].resize(p.cache_size); - ethash_prep_light(m_caches[_header.seedHash].data(), &p, _header.seedHash.data()); - writeFile(memoFile, m_caches[_header.seedHash]); - } - } - return m_caches[_header.seedHash]; - } - - byte const* full(BlockInfo const& _header) - { - RecursiveGuard l(x_this); - if (!m_fulls.count(_header.seedHash)) - { - if (!m_fulls.empty()) - { - delete [] m_fulls.begin()->second.data(); - m_fulls.erase(m_fulls.begin()); - } - std::string memoFile = getDataDir() + "/ethashcache/" + toHex(_header.seedHash.ref().cropped(0, 4)) + ".full"; - m_fulls[_header.seedHash] = contentsNew(memoFile); - if (!m_fulls[_header.seedHash]) - { - ethash_params p = params((unsigned)_header.number); - m_fulls[_header.seedHash] = bytesRef(new byte[p.full_size], p.full_size); - auto c = cache(_header); - ethash_prep_full(m_fulls[_header.seedHash].data(), &p, c.data()); - writeFile(memoFile, m_fulls[_header.seedHash]); - } - } - return m_fulls[_header.seedHash].data(); - } - - static ethash_params params(BlockInfo const& _header) - { - return params((unsigned)_header.number); - } - - static ethash_params params(unsigned _n) - { - ethash_params p; - p.cache_size = ethash_get_cachesize(_n); - p.full_size = ethash_get_datasize(_n); - return p; - } - -private: - static Ethasher* s_this; - RecursiveMutex x_this; - std::map m_caches; - std::map m_fulls; -}; - -Ethasher* Ethasher::s_this = nullptr; - bool Ethash::verify(BlockInfo const& _header) { - bigint boundary = (bigint(1) << 256) / _header.difficulty; - auto e = eval(_header, _header.nonce); - return (u256)e.value <= boundary && e.mixHash == _header.mixHash; -} - -Ethash::Result Ethash::eval(BlockInfo const& _header, Nonce const& _nonce) -{ - auto p = Ethasher::params(_header); - ethash_return_value r; - ethash_compute_light(&r, Ethasher::get()->cache(_header).data(), &p, _header.headerHash(WithoutNonce).data(), (uint64_t)(u64)_nonce); - return Result{h256(r.result, h256::ConstructFromPointer), h256(r.mix_hash, h256::ConstructFromPointer)}; + return Ethasher::verify(_header); } std::pair Ethash::mine(BlockInfo const& _header, unsigned _msTimeout, bool _continue, bool _turbo) { - auto h = _header.headerHash(WithoutNonce); - auto p = Ethasher::params(_header); - auto d = Ethasher::get()->full(_header); + Ethasher::Miner m(_header); std::pair ret; static std::mt19937_64 s_eng((time(0) + *reinterpret_cast(m_last.data()))); @@ -152,17 +66,15 @@ std::pair Ethash::mine(BlockInfo const& _header, unsign std::this_thread::sleep_for(std::chrono::milliseconds(_msTimeout * 90 / 100)); double best = 1e99; // high enough to be effectively infinity :) Proof result; - ethash_return_value ethashReturn; unsigned hashCount = 0; for (; (std::chrono::steady_clock::now() - startTime) < std::chrono::milliseconds(_msTimeout) && _continue; tryNonce++, hashCount++) { - ethash_compute_full(ðashReturn, d, &p, h.data(), tryNonce); - u256 val(h256(ethashReturn.result, h256::ConstructFromPointer)); + u256 val(m.mine(tryNonce)); best = std::min(best, log2((double)val)); if (val <= boundary) { ret.first.completed = true; - result.mixHash = h256(ethashReturn.mix_hash, h256::ConstructFromPointer); + result.mixHash = m.lastMixHash(); result.nonce = u64(tryNonce); break; } diff --git a/libethcore/ProofOfWork.h b/libethcore/ProofOfWork.h index 7006f6f61..250ddb73d 100644 --- a/libethcore/ProofOfWork.h +++ b/libethcore/ProofOfWork.h @@ -49,20 +49,12 @@ struct MineInfo class Ethash { public: - // bit-compatible with ethash_return_value struct Proof { Nonce nonce; h256 mixHash; }; - struct Result - { - h256 value; - h256 mixHash; - }; - static Result eval(BlockInfo const& _header) { return eval(_header, _header.nonce); } - static Result eval(BlockInfo const& _header, Nonce const& _nonce); static bool verify(BlockInfo const& _header); std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r.nonce; _header.mixHash = _r.mixHash; } @@ -78,9 +70,7 @@ public: using Proof = Nonce; static bool verify(BlockInfo const& _header) { return (bigint)(u256)Evaluator::eval(_header.headerHash(WithoutNonce), _header.nonce) <= (bigint(1) << 256) / _header.difficulty; } - inline std::pair mine(BlockInfo const& _header, unsigned _msTimeout = 100, bool _continue = true, bool _turbo = false); - static void assignResult(Proof const& _r, BlockInfo& _header) { _header.nonce = _r; } protected: diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 93263d385..84c95ed14 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -346,14 +346,17 @@ h256s BlockChain::import(bytes const& _block, OverlayDB const& _db) m_receipts[newHash] = br; } - m_blocksDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(h256(bi.number), ExtraBlockHash), (ldb::Slice)dev::ref(m_blockHashes[h256(bi.number)].rlp())); - for (auto const& h: tas) - m_extrasDB->Put(m_writeOptions, toSlice(h, ExtraTransactionAddress), (ldb::Slice)dev::ref(m_transactionAddresses[h].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); - m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)dev::ref(m_details[newHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(newHash, 3), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); + m_extrasDB->Put(m_writeOptions, toSlice(newHash, 4), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); + m_db->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); + RLP blockRLP(_block); + TransactionAddress ta; + ta.blockHash = newHash; + for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index) + m_extrasDB->Put(m_writeOptions, toSlice(sha3(blockRLP[1][ta.index].data()), 5), (ldb::Slice)dev::ref(ta.rlp())); #if ETH_PARANOIA checkConsistency(); diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 20c41b553..6c95af621 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -62,17 +62,8 @@ std::map const& genesisState(); ldb::Slice toSlice(h256 _h, unsigned _sub = 0); -using BlocksHash = std::map; using TransactionHashes = h256s; -enum { - ExtraDetails = 0, - ExtraBlockHash, - ExtraTransactionAddress, - ExtraLogBlooms, - ExtraReceipts -}; - /** * @brief Implements the blockchain database. All data this gives is disk-backed. * @threadsafe @@ -128,11 +119,12 @@ public: TransactionHashes transactionHashes(h256 _hash) const { auto b = block(_hash); RLP rlp(b); h256s ret; for (auto t: rlp[1]) ret.push_back(sha3(t.data())); return ret; } TransactionHashes transactionHashes() const { return transactionHashes(currentHash()); } - /// Get a list of transaction hashes for a given block. Thread-safe. - h256 numberHash(u256 _index) const { if (!_index) return genesisHash(); return queryExtras(h256(_index), m_blockHashes, x_blockHashes, NullBlockHash).value; } + /// Get a block (RLP format) for the given hash (or the most recent mined if none given). Thread-safe. + bytes block(h256 _hash) const; + bytes block() const { return block(currentHash()); } /// Get a transaction from its hash. Thread-safe. - bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); } + bytes transaction(h256 _transactionHash) const { TransactionAddress ta = queryExtras(_transactionHash, m_transactionAddresses, x_transactionAddresses, NullTransactionAddress); if (!ta) return bytes(); return transaction(ta.blockHash, ta.index); } /// Get a block's transaction (RLP format) for the given block hash (or the most recent mined if none given) & index. Thread-safe. bytes transaction(h256 _blockHash, unsigned _i) const { bytes b = block(_blockHash); return RLP(b)[1][_i].data().toBytes(); } @@ -225,20 +217,10 @@ private: mutable BlockLogBloomsHash m_logBlooms; mutable SharedMutex x_receipts; mutable BlockReceiptsHash m_receipts; - mutable SharedMutex x_transactionAddresses; + mutable boost::shared_mutex x_transactionAddresses; mutable TransactionAddressHash m_transactionAddresses; - mutable SharedMutex x_blockHashes; - mutable BlockHashHash m_blockHashes; - - using CacheID = std::pair; - mutable Mutex x_cacheUsage; - mutable std::deque> m_cacheUsage; - mutable std::set m_inUse; - void noteUsed(h256 const& _h, unsigned _extra = (unsigned)-1) const; - std::chrono::system_clock::time_point m_lastCollection; - - void updateStats() const; - mutable Statistics m_lastStats; + mutable boost::shared_mutex x_cache; + mutable std::map m_cache; /// The disk DBs. Thread-safe, so no need for locks. ldb::DB* m_blocksDB; diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 2ea558a14..a64519b8d 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -97,17 +97,27 @@ struct TransactionAddress static const unsigned size = 67; }; +struct TransactionAddress +{ + TransactionAddress() {} + TransactionAddress(RLP const& _rlp) { blockHash = _rlp[0].toHash(); index = _rlp[1].toInt(); } + bytes rlp() const { RLPStream s(2); s << blockHash << index; return s.out(); } + + explicit operator bool() const { return !!blockHash; } + + h256 blockHash; + unsigned index = 0; +}; + using BlockDetailsHash = std::map; using BlockLogBloomsHash = std::map; using BlockReceiptsHash = std::map; using TransactionAddressHash = std::map; -using BlockHashHash = std::map; static const BlockDetails NullBlockDetails; static const BlockLogBlooms NullBlockLogBlooms; static const BlockReceipts NullBlockReceipts; static const TransactionAddress NullTransactionAddress; -static const BlockHash NullBlockHash; } } diff --git a/test/dagger.cpp b/test/dagger.cpp index 720abbbaa..dec753fe7 100644 --- a/test/dagger.cpp +++ b/test/dagger.cpp @@ -41,16 +41,16 @@ BOOST_AUTO_TEST_SUITE(DashimotoTests) BOOST_AUTO_TEST_CASE(basic_test) { -#if 0 - cnote << "Testing ProofOfWork..."; - // Test dagger - { - auto s = steady_clock::now(); - cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)0); - cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - cout << hex << ProofOfWork().eval((h256)(u256)1, (h256)(u256)1); - cout << " " << dec << duration_cast(steady_clock::now() - s).count() << " ms" << endl; - } + string testPath = test::getTestPath(); + + testPath += "/PoWTests"; + + cnote << "Testing Secure Trie..."; + js::mValue v; + string s = asString(contents(testPath + "/ethash_tests.json")); + BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of 'ethash_tests.json' is empty. Have you cloned the 'tests' repo branch develop?"); + js::read_string(s, v); + for (auto& i: v.get_obj()) { cnote << i.first; js::mObject& o = i.second.get_obj(); @@ -78,8 +78,6 @@ BOOST_AUTO_TEST_CASE(basic_test) BOOST_REQUIRE_EQUAL(r.value, result); BOOST_REQUIRE_EQUAL(r.mixHash, header.mixHash); } -#endif - return 0; } BOOST_AUTO_TEST_SUITE_END()